timocratic-color 1.4.1.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.
@@ -0,0 +1,223 @@
1
+ #--
2
+ # Color
3
+ # Colour management with Ruby
4
+ # http://rubyforge.org/projects/color
5
+ # Version 1.4.0
6
+ #
7
+ # Licensed under a MIT-style licence. See Licence.txt in the main
8
+ # distribution for full licensing information.
9
+ #
10
+ # Copyright (c) 2005 - 2007 Austin Ziegler and Matt Lyon
11
+ #
12
+ # $Id: test_all.rb 55 2007-02-03 23:29:34Z austin $
13
+ #++
14
+
15
+ # An HSL colour object. Internally, the hue (#h), saturation (#s), and
16
+ # luminosity/lightness (#l) values are dealt with as fractional values in
17
+ # the range 0..1.
18
+ class Color::HSL
19
+ class << self
20
+ # Creates an HSL colour object from fractional values 0..1.
21
+ def from_fraction(h = 0.0, s = 0.0, l = 0.0)
22
+ colour = Color::HSL.new
23
+ colour.h = h
24
+ colour.s = s
25
+ colour.l = l
26
+ colour
27
+ end
28
+ end
29
+
30
+ # Compares the other colour to this one. The other colour will be
31
+ # converted to HSL before comparison, so the comparison between a HSL
32
+ # colour and a non-HSL colour will be approximate and based on the other
33
+ # colour's #to_hsl conversion. If there is no #to_hsl conversion, this
34
+ # will raise an exception. This will report that two HSL values are
35
+ # equivalent if all component values are within Color::COLOR_TOLERANCE of
36
+ # each other.
37
+ def ==(other)
38
+ other = other.to_hsl
39
+ other.kind_of?(Color::HSL) and
40
+ ((@h - other.h).abs <= Color::COLOR_TOLERANCE) and
41
+ ((@s - other.s).abs <= Color::COLOR_TOLERANCE) and
42
+ ((@l - other.l).abs <= Color::COLOR_TOLERANCE)
43
+ end
44
+
45
+ # Creates an HSL colour object from the standard values of degrees and
46
+ # percentages (e.g., 145 deg, 30%, 50%).
47
+ def initialize(h = 0, s = 0, l = 0)
48
+ @h = h / 360.0
49
+ @s = s / 100.0
50
+ @l = l / 100.0
51
+ end
52
+
53
+ # Present the colour as an HTML/CSS colour string.
54
+ def html
55
+ to_rgb.html
56
+ end
57
+
58
+ # Present the colour as an RGB HTML/CSS colour string (e.g., "rgb(0%, 50%,
59
+ # 100%)"). Note that this will perform a #to_rgb operation using the
60
+ # default conversion formula.
61
+ def css_rgb
62
+ to_rgb.css_rgb
63
+ end
64
+
65
+ # Present the colour as an RGBA (with alpha) HTML/CSS colour string (e.g.,
66
+ # "rgb(0%, 50%, 100%, 1)"). Note that this will perform a #to_rgb
67
+ # operation using the default conversion formula.
68
+ def css_rgba
69
+ to_rgb.css_rgba
70
+ end
71
+
72
+ # Present the colour as an HSL HTML/CSS colour string (e.g., "hsl(180,
73
+ # 25%, 35%)").
74
+ def css_hsl
75
+ "hsl(%3.2f, %3.2f%%, %3.2f%%)" % [ hue, saturation, luminosity ]
76
+ end
77
+
78
+ # Present the colour as an HSLA (with alpha) HTML/CSS colour string (e.g.,
79
+ # "hsla(180, 25%, 35%, 1)").
80
+ def css_hsla
81
+ "hsla(%3.2f, %3.2f%%, %3.2f%%, %3.2f)" % [ hue, saturation, luminosity, 1 ]
82
+ end
83
+
84
+ # Converting to HSL as adapted from Foley and Van-Dam from
85
+ # http://www.bobpowell.net/RGBHSB.htm.
86
+ #
87
+ # NOTE:
88
+ # * If the colour's luminosity is near zero, the colour is always black.
89
+ # * If the colour's luminosity is near one, the colour is always white.
90
+ # * If the colour's saturation is near zero, the colour is always a shade
91
+ # of grey and is based only on the luminosity of the colour.
92
+ #
93
+ def to_rgb(ignored = nil)
94
+ return Color::RGB.new if Color.near_zero_or_less?(@l)
95
+ return Color::RGB.new(0xff, 0xff, 0xff) if Color.near_one_or_more?(@l)
96
+ return Color::RGB.from_fraction(@l, @l, @l) if Color.near_zero?(@s)
97
+
98
+ # Is the value less than 0.5?
99
+ if Color.near_zero_or_less?(@l - 0.5)
100
+ tmp2 = @l * (1.0 + @s.to_f)
101
+ else
102
+ tmp2 = @l + @s - (@l * @s.to_f)
103
+ end
104
+ tmp1 = 2.0 * @l - tmp2
105
+
106
+ tmp3 = [ @h + (1.0 / 3.0), @h, @h - (1.0 / 3.0) ]
107
+
108
+ rgb = tmp3.map { |hue|
109
+ hue += 1.0 if Color.near_zero_or_less?(hue)
110
+ hue -= 1.0 if Color.near_one_or_more?(hue)
111
+
112
+ if Color.near_zero_or_less?((6.0 * hue) - 1.0)
113
+ tmp1 + ((tmp2 - tmp1) * hue * 6.0)
114
+ elsif Color.near_zero_or_less?((2.0 * hue) - 1.0)
115
+ tmp2
116
+ elsif Color.near_zero_or_less?((3.0 * hue) - 2.0)
117
+ tmp1 + (tmp2 - tmp1) * ((2 / 3.0) - hue) * 6.0
118
+ else
119
+ tmp1
120
+ end
121
+ }
122
+
123
+ Color::RGB.from_fraction(*rgb)
124
+ end
125
+
126
+ # Converts to RGB then YIQ.
127
+ def to_yiq
128
+ to_rgb.to_yiq
129
+ end
130
+
131
+ # Converts to RGB then CMYK.
132
+ def to_cmyk
133
+ to_rgb.to_cmyk
134
+ end
135
+
136
+ # Returns the luminosity (#l) of the colour.
137
+ def brightness
138
+ @l
139
+ end
140
+ def to_greyscale
141
+ Color::GrayScale.from_fraction(@l)
142
+ end
143
+ alias to_grayscale to_greyscale
144
+
145
+ # Returns the hue of the colour in degrees.
146
+ def hue
147
+ @h * 360.0
148
+ end
149
+ # Returns the hue of the colour in the range 0.0 .. 1.0.
150
+ def h
151
+ @h
152
+ end
153
+ # Sets the hue of the colour in degrees. Colour is perceived as a wheel,
154
+ # so values should be set properly even with negative degree values.
155
+ def hue=(hh)
156
+ hh = hh / 360.0
157
+
158
+ hh += 1.0 if hh < 0.0
159
+ hh -= 1.0 if hh > 1.0
160
+
161
+ @h = Color.normalize(hh)
162
+ end
163
+ # Sets the hue of the colour in the range 0.0 .. 1.0.
164
+ def h=(hh)
165
+ @h = Color.normalize(hh)
166
+ end
167
+ # Returns the percentage of saturation of the colour.
168
+ def saturation
169
+ @s * 100.0
170
+ end
171
+ # Returns the saturation of the colour in the range 0.0 .. 1.0.
172
+ def s
173
+ @s
174
+ end
175
+ # Sets the percentage of saturation of the colour.
176
+ def saturation=(ss)
177
+ @s = Color.normalize(ss / 100.0)
178
+ end
179
+ # Sets the saturation of the colour in the ragne 0.0 .. 1.0.
180
+ def s=(ss)
181
+ @s = Color.normalize(ss)
182
+ end
183
+
184
+ # Returns the percentage of luminosity of the colour.
185
+ def luminosity
186
+ @l * 100.0
187
+ end
188
+ alias lightness luminosity
189
+ # Returns the luminosity of the colour in the range 0.0 .. 1.0.
190
+ def l
191
+ @l
192
+ end
193
+ # Sets the percentage of luminosity of the colour.
194
+ def luminosity=(ll)
195
+ @l = Color.normalize(ll / 100.0)
196
+ end
197
+ alias lightness= luminosity= ;
198
+ # Sets the luminosity of the colour in the ragne 0.0 .. 1.0.
199
+ def l=(ll)
200
+ @l = Color.normalize(ll)
201
+ end
202
+
203
+ def to_hsl
204
+ self
205
+ end
206
+
207
+ def inspect
208
+ "HSL [%.2f deg, %.2f%%, %.2f%%]" % [ hue, saturation, luminosity ]
209
+ end
210
+
211
+ # Mix the mask colour (which will be converted to an HSL colour) with the
212
+ # current colour at the stated mix percentage as a decimal value.
213
+ #
214
+ # NOTE:: This differs from Color::RGB#mix_with.
215
+ def mix_with(color, mix_percent = 0.5)
216
+ color = color.to_hsl
217
+ _h = ((color.h - self.h) * mix_percent) + self.h
218
+ _s = ((color.s - self.s) * mix_percent) + self.s
219
+ _l = ((color.l - self.l) * mix_percent) + self.l
220
+
221
+ self.class.from_fraction(_h, _s, _l)
222
+ end
223
+ end
@@ -0,0 +1,18 @@
1
+ #--
2
+ # Color
3
+ # Colour management with Ruby
4
+ # http://rubyforge.org/projects/color
5
+ # Version 1.4.0
6
+ #
7
+ # Licensed under a MIT-style licence. See Licence.txt in the main
8
+ # distribution for full licensing information.
9
+ #
10
+ # Copyright (c) 2005 - 2007 Austin Ziegler and Matt Lyon
11
+ #
12
+ # $Id: test_all.rb 55 2007-02-03 23:29:34Z austin $
13
+ #++
14
+
15
+ require 'color'
16
+
17
+ module Color::Palette
18
+ end
@@ -0,0 +1,274 @@
1
+ #--
2
+ # Color
3
+ # Colour management with Ruby
4
+ # http://rubyforge.org/projects/color
5
+ # Version 1.4.0
6
+ #
7
+ # Licensed under a MIT-style licence. See Licence.txt in the main
8
+ # distribution for full licensing information.
9
+ #
10
+ # Copyright (c) 2005 - 2007 Austin Ziegler and Matt Lyon
11
+ #
12
+ # $Id: test_all.rb 55 2007-02-03 23:29:34Z austin $
13
+ #++
14
+
15
+ require 'color/palette'
16
+
17
+ # A class that can read an Adobe Color palette file (used for Photoshop
18
+ # swatches) and provide a Hash-like interface to the contents. Not all
19
+ # colour formats in ACO files are supported. Based largely off the
20
+ # information found by Larry Tesler[http://www.nomodes.com/aco.html].
21
+ #
22
+ # Not all Adobe Color files have named colours; all named entries are
23
+ # returned as an array.
24
+ #
25
+ # pal = Color::Palette::AdobeColor.from_file(my_aco_palette)
26
+ # pal[0] => Color::RGB<...>
27
+ # pal["white"] => [ Color::RGB<...> ]
28
+ # pal["unknown"] => [ Color::RGB<...>, Color::RGB<...>, ... ]
29
+ #
30
+ # AdobeColor palettes are always indexable by insertion order (an integer
31
+ # key).
32
+ #
33
+ # Version 2 palettes use UTF-16 colour names.
34
+ class Color::Palette::AdobeColor
35
+ include Enumerable
36
+
37
+ class << self
38
+ # Create an AdobeColor palette object from the named file.
39
+ def from_file(filename)
40
+ File.open(filename, "rb") { |io| Color::Palette::AdobeColor.from_io(io) }
41
+ end
42
+
43
+ # Create an AdobeColor palette object from the provided IO.
44
+ def from_io(io)
45
+ Color::Palette::AdobeColor.new(io.read)
46
+ end
47
+ end
48
+
49
+ # Returns statistics about the nature of the colours loaded.
50
+ attr_reader :statistics
51
+ # Contains the "lost" colours in the palette. These colours could not be
52
+ # properly loaded (e.g., L*a*b* is not supported by Color, so it is
53
+ # "lost") or are not understood by the algorithms.
54
+ attr_reader :lost
55
+
56
+ # Use this to convert the unsigned word to the signed word, if necessary.
57
+ UwToSw = proc { |n| (n >= (2 ** 16)) ? n - (2 ** 32) : n } #:nodoc:
58
+
59
+ # Create a new AdobeColor palette from the palette file as a string.
60
+ def initialize(palette)
61
+ @colors = []
62
+ @names = {}
63
+ @statistics = Hash.new(0)
64
+ @lost = []
65
+ @order = []
66
+ @version = nil
67
+
68
+ class << palette
69
+ def readwords(count = 1)
70
+ @offset ||= 0
71
+ raise IndexError if @offset >= self.size
72
+ val = self[@offset, count * 2]
73
+ raise IndexError if val.nil? or val.size < (count * 2)
74
+ val = val.unpack("n" * count)
75
+ @offset += count * 2
76
+ val
77
+ end
78
+
79
+ def readutf16(count = 1)
80
+ @offset ||= 0
81
+ raise IndexError if @offset >= self.size
82
+ val = self[@offset, count * 2]
83
+ raise IndexError if val.nil? or val.size < (count * 2)
84
+ @offset += count * 2
85
+ val
86
+ end
87
+ end
88
+
89
+ @version, count = palette.readwords 2
90
+
91
+ raise "Unknown AdobeColor palette version #@version." unless @version.between?(1, 2)
92
+
93
+ count.times do
94
+ space, w, x, y, z = palette.readwords 5
95
+ name = nil
96
+ if @version == 2
97
+ raise IndexError unless palette.readwords == [ 0 ]
98
+ len = palette.readwords
99
+ name = palette.readutf16(len[0] - 1)
100
+ raise IndexError unless palette.readwords == [ 0 ]
101
+ end
102
+
103
+ color = case space
104
+ when 0 then # RGB
105
+ @statistics[:rgb] += 1
106
+
107
+ Color::RGB.new(w / 256, x / 256, y / 256)
108
+ when 1 then # HS[BV] -- Convert to RGB
109
+ @statistics[:hsb] += 1
110
+
111
+ h = w / 65535.0
112
+ s = x / 65535.0
113
+ v = y / 65535.0
114
+
115
+ if defined?(Color::HSB)
116
+ Color::HSB.from_fraction(h, s, v)
117
+ else
118
+ @statistics[:converted] += 1
119
+ if Color.near_zero_or_less?(s)
120
+ Color::RGB.from_fraction(v, v, v)
121
+ else
122
+ if Color.near_one_or_more?(h)
123
+ vh = 0
124
+ else
125
+ vh = h * 6.0
126
+ end
127
+
128
+ vi = vh.floor
129
+ v1 = v.to_f * (1 - s.to_f)
130
+ v2 = v.to_f * (1 - s.to_f * (vh - vi))
131
+ v3 = v.to_f * (1 - s.to_f * (1 - (vh - vi)))
132
+
133
+ case vi
134
+ when 0 then Color::RGB.from_fraction(v, v3, v1)
135
+ when 1 then Color::RGB.from_fraction(v2, v, v1)
136
+ when 2 then Color::RGB.from_fraction(v1, v, v3)
137
+ when 3 then Color::RGB.from_fraction(v1, v2, v)
138
+ when 4 then Color::RGB.from_fraction(v3, v1, v)
139
+ else Color::RGB.from_fraction(v, v1, v2)
140
+ end
141
+ end
142
+ end
143
+ when 2 then # CMYK
144
+ @statistics[:cmyk] += 1
145
+ Color::CMYK.from_percent(100 - (w / 655.35),
146
+ 100 - (x / 655.35),
147
+ 100 - (y / 655.35),
148
+ 100 - (z / 655.35))
149
+ when 7 then # L*a*b*
150
+ @statistics[:lab] += 1
151
+
152
+ l = [w, 10000].min / 100.0
153
+ a = [[-12800, UwToSw[x]].max, 12700].min / 100.0
154
+ b = [[-12800, UwToSw[x]].max, 12700].min / 100.0
155
+
156
+ if defined? Color::Lab
157
+ Color::Lab.new(l, a, b)
158
+ else
159
+ [ space, w, x, y, z ]
160
+ end
161
+ when 8 then # Grayscale
162
+ @statistics[:gray] += 1
163
+
164
+ g = [w, 10000].min / 100.0
165
+ Color::GrayScale.new(g)
166
+ when 9 then # Wide CMYK
167
+ @statistics[:wcmyk] += 1
168
+
169
+ c = [w, 10000].min / 100.0
170
+ m = [x, 10000].min / 100.0
171
+ y = [y, 10000].min / 100.0
172
+ k = [z, 10000].min / 100.0
173
+ Color::CMYK.from_percent(c, m, y, k)
174
+ else
175
+ @statistics[space] += 1
176
+ [ space, w, x, y, z ]
177
+ end
178
+
179
+ @order << [ color, name ]
180
+
181
+ if color.kind_of? Array
182
+ @lost << color
183
+ else
184
+ @colors << color
185
+
186
+ if name
187
+ @names[name] ||= []
188
+ @names[name] << color
189
+ end
190
+ end
191
+ end
192
+ end
193
+
194
+ # Provides the colour or colours at the provided selectors.
195
+ def values_at(*selectors)
196
+ @colors.values_at(*selectors)
197
+ end
198
+
199
+ # If a Numeric +key+ is provided, the single colour value at that position
200
+ # will be returned. If a String +key+ is provided, the colour set (an
201
+ # array) for that colour name will be returned.
202
+ def [](key)
203
+ if key.kind_of?(Numeric)
204
+ @colors[key]
205
+ else
206
+ @names[key]
207
+ end
208
+ end
209
+
210
+ # Loops through each colour.
211
+ def each
212
+ @colors.each { |el| yield el }
213
+ end
214
+
215
+ # Loops through each named colour set.
216
+ def each_name #:yields color_name, color_set:#
217
+ @names.each { |color_name, color_set| yield color_name, color_set }
218
+ end
219
+
220
+ def size
221
+ @colors.size
222
+ end
223
+
224
+ attr_reader :version
225
+
226
+ def to_aco(version = @version) #:nodoc:
227
+ res = ""
228
+
229
+ res << [ version, @order.size ].pack("nn")
230
+
231
+ @order.each do |cnpair|
232
+ color, name = *cnpair
233
+
234
+ # Note: HSB and CMYK formats are lost by the conversions performed on
235
+ # import. They are turned into RGB and WCMYK, respectively.
236
+
237
+ cstr = case color
238
+ when Array
239
+ color
240
+ when Color::RGB
241
+ r = [(color.red * 256).round, 65535].min
242
+ g = [(color.green * 256).round, 65535].min
243
+ b = [(color.blue * 256).round, 65535].min
244
+ [ 0, r, g, b, 0 ]
245
+ when Color::GrayScale
246
+ g = [(color.gray * 100).round, 10000].min
247
+ [ 8, g, 0, 0, 0 ]
248
+ when Color::CMYK
249
+ c = [(color.cyan * 100).round, 10000].min
250
+ m = [(color.magenta * 100).round, 10000].min
251
+ y = [(color.yellow * 100).round, 10000].min
252
+ k = [(color.black * 100).round, 10000].min
253
+ [ 9, c, m, y, k ]
254
+ end
255
+ cstr = cstr.pack("nnnnn")
256
+
257
+ nstr = ""
258
+
259
+ if version == 2
260
+ if (name.size / 2 * 2) == name.size # only where s[0] == byte!
261
+ nstr << [ 0, (name.size / 2) + 1 ].pack("nn")
262
+ nstr << name
263
+ nstr << [ 0 ].pack("n")
264
+ else
265
+ nstr << [ 0, 1, 0 ].pack("nnn")
266
+ end
267
+ end
268
+
269
+ res << cstr << nstr
270
+ end
271
+
272
+ res
273
+ end
274
+ end