timocratic-color 1.4.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,455 @@
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 RGB colour object.
16
+ class Color::RGB
17
+ # The format of a DeviceRGB colour for PDF. In color-tools 2.0 this will
18
+ # be removed from this package and added back as a modification by the
19
+ # PDF::Writer package.
20
+ PDF_FORMAT_STR = "%.3f %.3f %.3f %s"
21
+
22
+ class << self
23
+ # Creates an RGB colour object from percentages 0..100.
24
+ #
25
+ # Color::RGB.from_percentage(10, 20 30)
26
+ def from_percentage(r = 0, g = 0, b = 0)
27
+ from_fraction(r / 100.0, g / 100.0, b / 100.0)
28
+ end
29
+
30
+ # Creates an RGB colour object from fractional values 0..1.
31
+ #
32
+ # Color::RGB.from_fraction(.3, .2, .1)
33
+ def from_fraction(r = 0.0, g = 0.0, b = 0.0)
34
+ colour = Color::RGB.new
35
+ colour.r = r
36
+ colour.g = g
37
+ colour.b = b
38
+ colour
39
+ end
40
+
41
+ # Creates an RGB colour object from an HTML colour descriptor (e.g.,
42
+ # <tt>"fed"</tt> or <tt>"#cabbed;"</tt>.
43
+ #
44
+ # Color::RGB.from_html("fed")
45
+ # Color::RGB.from_html("#fed")
46
+ # Color::RGB.from_html("#cabbed")
47
+ # Color::RGB.from_html("cabbed")
48
+ def from_html(html_colour)
49
+ html_colour = html_colour.gsub(%r{[#;]}, '')
50
+ case html_colour.size
51
+ when 3
52
+ colours = html_colour.scan(%r{[0-9A-Fa-f]}).map { |el| (el * 2).to_i(16) }
53
+ when 6
54
+ colours = html_colour.scan(%r<[0-9A-Fa-f]{2}>).map { |el| el.to_i(16) }
55
+ else
56
+ raise ArgumentError
57
+ end
58
+
59
+ Color::RGB.new(*colours)
60
+ end
61
+ end
62
+
63
+ # Compares the other colour to this one. The other colour will be
64
+ # converted to RGB before comparison, so the comparison between a RGB
65
+ # colour and a non-RGB colour will be approximate and based on the other
66
+ # colour's default #to_rgb conversion. If there is no #to_rgb conversion,
67
+ # this will raise an exception. This will report that two RGB colours are
68
+ # equivalent if all component values are within COLOR_TOLERANCE of each
69
+ # other.
70
+ def ==(other)
71
+ other = other.to_rgb
72
+ other.kind_of?(Color::RGB) and
73
+ ((@r - other.r).abs <= Color::COLOR_TOLERANCE) and
74
+ ((@g - other.g).abs <= Color::COLOR_TOLERANCE) and
75
+ ((@b - other.b).abs <= Color::COLOR_TOLERANCE)
76
+ end
77
+
78
+ # Creates an RGB colour object from the standard range 0..255.
79
+ #
80
+ # Color::RGB.new(32, 64, 128)
81
+ # Color::RGB.new(0x20, 0x40, 0x80)
82
+ def initialize(r = 0, g = 0, b = 0)
83
+ @r = r / 255.0
84
+ @g = g / 255.0
85
+ @b = b / 255.0
86
+ end
87
+
88
+ # Present the colour as a DeviceRGB fill colour string for PDF. This will
89
+ # be removed from the default package in color-tools 2.0.
90
+ def pdf_fill
91
+ PDF_FORMAT_STR % [ @r, @g, @b, "rg" ]
92
+ end
93
+
94
+ # Present the colour as a DeviceRGB stroke colour string for PDF. This
95
+ # will be removed from the default package in color-tools 2.0.
96
+ def pdf_stroke
97
+ PDF_FORMAT_STR % [ @r, @g, @b, "RG" ]
98
+ end
99
+
100
+ # Present the colour as an HTML/CSS colour string.
101
+ def html
102
+ r = (@r * 255).round
103
+ r = 255 if r > 255
104
+
105
+ g = (@g * 255).round
106
+ g = 255 if g > 255
107
+
108
+ b = (@b * 255).round
109
+ b = 255 if b > 255
110
+
111
+ "#%02x%02x%02x" % [ r, g, b ]
112
+ end
113
+
114
+ # Present the colour as an RGB HTML/CSS colour string (e.g., "rgb(0%, 50%,
115
+ # 100%)"). Note that this will perform a #to_rgb operation using the
116
+ # default conversion formula.
117
+ def css_rgb
118
+ "rgb(%3.2f%%, %3.2f%%, %3.2f%%)" % [ red_p, green_p, blue_p ]
119
+ end
120
+
121
+ # Present the colour as an RGBA (with alpha) HTML/CSS colour string (e.g.,
122
+ # "rgb(0%, 50%, 100%, 1)"). Note that this will perform a #to_rgb
123
+ # operation using the default conversion formula.
124
+ def css_rgba
125
+ "rgba(%3.2f%%, %3.2f%%, %3.2f%%, %3.2f)" % [ red_p, green_p, blue_p, 1 ]
126
+ end
127
+
128
+ # Present the colour as an HSL HTML/CSS colour string (e.g., "hsl(180,
129
+ # 25%, 35%)"). Note that this will perform a #to_hsl operation using the
130
+ # default conversion formula.
131
+ def css_hsl
132
+ to_hsl.css_hsl
133
+ end
134
+
135
+ # Present the colour as an HSLA (with alpha) HTML/CSS colour string (e.g.,
136
+ # "hsla(180, 25%, 35%, 1)"). Note that this will perform a #to_hsl
137
+ # operation using the default conversion formula.
138
+ def css_hsla
139
+ to_hsl.css_hsla
140
+ end
141
+
142
+ # Converts the RGB colour to CMYK. Most colour experts strongly suggest
143
+ # that this is not a good idea (some even suggesting that it's a very bad
144
+ # idea). CMYK represents additive percentages of inks on white paper,
145
+ # whereas RGB represents mixed colour intensities on a black screen.
146
+ #
147
+ # However, the colour conversion can be done. The basic method is
148
+ # multi-step:
149
+ #
150
+ # 1. Convert the R, G, and B components to C, M, and Y components.
151
+ # c = 1.0 - r
152
+ # m = 1.0 - g
153
+ # y = 1.0 - b
154
+ # 2. Compute the minimum amount of black (K) required to smooth the colour
155
+ # in inks.
156
+ # k = min(c, m, y)
157
+ # 3. Perform undercolour removal on the C, M, and Y components of the
158
+ # colours because less of each colour is needed for each bit of black.
159
+ # Also, regenerate the black (K) based on the undercolour removal so
160
+ # that the colour is more accurately represented in ink.
161
+ # c = min(1.0, max(0.0, c - UCR(k)))
162
+ # m = min(1.0, max(0.0, m - UCR(k)))
163
+ # y = min(1.0, max(0.0, y - UCR(k)))
164
+ # k = min(1.0, max(0.0, BG(k)))
165
+ #
166
+ # The undercolour removal function and the black generation functions
167
+ # return a value based on the brightness of the RGB colour.
168
+ def to_cmyk
169
+ c = 1.0 - @r.to_f
170
+ m = 1.0 - @g.to_f
171
+ y = 1.0 - @b.to_f
172
+
173
+ k = [c, m, y].min
174
+ k = k - (k * brightness)
175
+
176
+ c = [1.0, [0.0, c - k].max].min
177
+ m = [1.0, [0.0, m - k].max].min
178
+ y = [1.0, [0.0, y - k].max].min
179
+ k = [1.0, [0.0, k].max].min
180
+
181
+ Color::CMYK.from_fraction(c, m, y, k)
182
+ end
183
+
184
+ def to_rgb(ignored = nil)
185
+ self
186
+ end
187
+
188
+ # Returns the YIQ (NTSC) colour encoding of the RGB value.
189
+ def to_yiq
190
+ y = (@r * 0.299) + (@g * 0.587) + (@b * 0.114)
191
+ i = (@r * 0.596) + (@g * -0.275) + (@b * -0.321)
192
+ q = (@r * 0.212) + (@g * -0.523) + (@b * 0.311)
193
+ Color::YIQ.from_fraction(y, i, q)
194
+ end
195
+
196
+ # Returns the HSL colour encoding of the RGB value. The conversions here
197
+ # are based on forumlas from http://www.easyrgb.com/math.php and
198
+ # elsewhere.
199
+ def to_hsl
200
+ min = [ @r, @g, @b ].min
201
+ max = [ @r, @g, @b ].max
202
+ delta = (max - min).to_f
203
+
204
+ lum = (max + min) / 2.0
205
+
206
+ if Color.near_zero?(delta) # close to 0.0, so it's a grey
207
+ hue = 0
208
+ sat = 0
209
+ else
210
+ if Color.near_zero_or_less?(lum - 0.5)
211
+ sat = delta / (max + min).to_f
212
+ else
213
+ sat = delta / (2 - max - min).to_f
214
+ end
215
+
216
+ # This is based on the conversion algorithm from
217
+ # http://en.wikipedia.org/wiki/HSV_color_space#Conversion_from_RGB_to_HSL_or_HSV
218
+ # Contributed by Adam Johnson
219
+ sixth = 1 / 6.0
220
+ if @r == max # Color.near_zero_or_less?(@r - max)
221
+ hue = (sixth * ((@g - @b) / delta))
222
+ hue += 1.0 if @g < @b
223
+ elsif @g == max # Color.near_zero_or_less(@g - max)
224
+ hue = (sixth * ((@b - @r) / delta)) + (1.0 / 3.0)
225
+ elsif @b == max # Color.near_zero_or_less?(@b - max)
226
+ hue = (sixth * ((@r - @g) / delta)) + (2.0 / 3.0)
227
+ end
228
+
229
+ hue += 1 if hue < 0
230
+ hue -= 1 if hue > 1
231
+ end
232
+ Color::HSL.from_fraction(hue, sat, lum)
233
+ end
234
+
235
+ # Mix the RGB hue with White so that the RGB hue is the specified
236
+ # percentage of the resulting colour. Strictly speaking, this isn't a
237
+ # darken_by operation.
238
+ def lighten_by(percent)
239
+ mix_with(White, percent)
240
+ end
241
+
242
+ # Mix the RGB hue with Black so that the RGB hue is the specified
243
+ # percentage of the resulting colour. Strictly speaking, this isn't a
244
+ # darken_by operation.
245
+ def darken_by(percent)
246
+ mix_with(Black, percent)
247
+ end
248
+
249
+ # Mix the mask colour (which must be an RGB object) with the current
250
+ # colour at the stated opacity percentage (0..100).
251
+ def mix_with(mask, opacity)
252
+ opacity /= 100.0
253
+ rgb = self.dup
254
+
255
+ rgb.r = (@r * opacity) + (mask.r * (1 - opacity))
256
+ rgb.g = (@g * opacity) + (mask.g * (1 - opacity))
257
+ rgb.b = (@b * opacity) + (mask.b * (1 - opacity))
258
+
259
+ rgb
260
+ end
261
+
262
+ # Returns the brightness value for a colour, a number between 0..1. Based
263
+ # on the Y value of YIQ encoding, representing luminosity, or perceived
264
+ # brightness.
265
+ #
266
+ # This may be modified in a future version of color-tools to use the
267
+ # luminosity value of HSL.
268
+ def brightness
269
+ to_yiq.y
270
+ end
271
+ # Convert to grayscale.
272
+ def to_grayscale
273
+ Color::GrayScale.from_fraction(to_hsl.l)
274
+ end
275
+ alias to_greyscale to_grayscale
276
+
277
+ # Returns a new colour with the brightness adjusted by the specified
278
+ # percentage. Negative percentages will darken the colour; positive
279
+ # percentages will brighten the colour.
280
+ #
281
+ # Color::RGB::DarkBlue.adjust_brightness(10)
282
+ # Color::RGB::DarkBlue.adjust_brightness(-10)
283
+ def adjust_brightness(percent)
284
+ percent /= 100.0
285
+ percent += 1.0
286
+ percent = [ percent, 2.0 ].min
287
+ percent = [ 0.0, percent ].max
288
+
289
+ hsl = to_hsl
290
+ hsl.l *= percent
291
+ hsl.to_rgb
292
+ end
293
+
294
+ # Returns a new colour with the saturation adjusted by the specified
295
+ # percentage. Negative percentages will reduce the saturation; positive
296
+ # percentages will increase the saturation.
297
+ #
298
+ # Color::RGB::DarkBlue.adjust_saturation(10)
299
+ # Color::RGB::DarkBlue.adjust_saturation(-10)
300
+ def adjust_saturation(percent)
301
+ percent /= 100.0
302
+ percent += 1.0
303
+ percent = [ percent, 2.0 ].min
304
+ percent = [ 0.0, percent ].max
305
+
306
+ hsl = to_hsl
307
+ hsl.s *= percent
308
+ hsl.to_rgb
309
+ end
310
+
311
+ # Returns a new colour with the hue adjusted by the specified percentage.
312
+ # Negative percentages will reduce the hue; positive percentages will
313
+ # increase the hue.
314
+ #
315
+ # Color::RGB::DarkBlue.adjust_hue(10)
316
+ # Color::RGB::DarkBlue.adjust_hue(-10)
317
+ def adjust_hue(percent)
318
+ percent /= 100.0
319
+ percent += 1.0
320
+ percent = [ percent, 2.0 ].min
321
+ percent = [ 0.0, percent ].max
322
+
323
+ hsl = to_hsl
324
+ hsl.h *= percent
325
+ hsl.to_rgb
326
+ end
327
+
328
+ # Returns the red component of the colour in the normal 0 .. 255 range.
329
+ def red
330
+ @r * 255.0
331
+ end
332
+ # Returns the red component of the colour as a percentage.
333
+ def red_p
334
+ @r * 100.0
335
+ end
336
+ # Returns the red component of the colour as a fraction in the range 0.0
337
+ # .. 1.0.
338
+ def r
339
+ @r
340
+ end
341
+ # Sets the red component of the colour in the normal 0 .. 255 range.
342
+ def red=(rr)
343
+ @r = Color.normalize(rr / 255.0)
344
+ end
345
+ # Sets the red component of the colour as a percentage.
346
+ def red_p=(rr)
347
+ @r = Color.normalize(rr / 100.0)
348
+ end
349
+ # Sets the red component of the colour as a fraction in the range 0.0 ..
350
+ # 1.0.
351
+ def r=(rr)
352
+ @r = Color.normalize(rr)
353
+ end
354
+
355
+ # Returns the green component of the colour in the normal 0 .. 255 range.
356
+ def green
357
+ @g * 255.0
358
+ end
359
+ # Returns the green component of the colour as a percentage.
360
+ def green_p
361
+ @g * 100.0
362
+ end
363
+ # Returns the green component of the colour as a fraction in the range 0.0
364
+ # .. 1.0.
365
+ def g
366
+ @g
367
+ end
368
+ # Sets the green component of the colour in the normal 0 .. 255 range.
369
+ def green=(gg)
370
+ @g = Color.normalize(gg / 255.0)
371
+ end
372
+ # Sets the green component of the colour as a percentage.
373
+ def green_p=(gg)
374
+ @g = Color.normalize(gg / 100.0)
375
+ end
376
+ # Sets the green component of the colour as a fraction in the range 0.0 ..
377
+ # 1.0.
378
+ def g=(gg)
379
+ @g = Color.normalize(gg)
380
+ end
381
+
382
+ # Returns the blue component of the colour in the normal 0 .. 255 range.
383
+ def blue
384
+ @b * 255.0
385
+ end
386
+ # Returns the blue component of the colour as a percentage.
387
+ def blue_p
388
+ @b * 100.0
389
+ end
390
+ # Returns the blue component of the colour as a fraction in the range 0.0
391
+ # .. 1.0.
392
+ def b
393
+ @b
394
+ end
395
+ # Sets the blue component of the colour in the normal 0 .. 255 range.
396
+ def blue=(bb)
397
+ @b = Color.normalize(bb / 255.0)
398
+ end
399
+ # Sets the blue component of the colour as a percentage.
400
+ def blue_p=(bb)
401
+ @b = Color.normalize(bb / 100.0)
402
+ end
403
+ # Sets the blue component of the colour as a fraction in the range 0.0 ..
404
+ # 1.0.
405
+ def b=(bb)
406
+ @b = Color.normalize(bb)
407
+ end
408
+
409
+ # Adds another colour to the current colour. The other colour will be
410
+ # converted to RGB before addition. This conversion depends upon a #to_rgb
411
+ # method on the other colour.
412
+ #
413
+ # The addition is done using the RGB Accessor methods to ensure a valid
414
+ # colour in the result.
415
+ def +(other)
416
+ other = other.to_rgb
417
+ rgb = self.dup
418
+
419
+ rgb.r += other.r
420
+ rgb.g += other.g
421
+ rgb.b += other.b
422
+
423
+ rgb
424
+ end
425
+
426
+ # Subtracts another colour to the current colour. The other colour will be
427
+ # converted to RGB before subtraction. This conversion depends upon a
428
+ # #to_rgb method on the other colour.
429
+ #
430
+ # The subtraction is done using the RGB Accessor methods to ensure a valid
431
+ # colour in the result.
432
+ def -(other)
433
+ other = other.to_rgb
434
+ rgb = self.dup
435
+
436
+ rgb.r -= other.r
437
+ rgb.g -= other.g
438
+ rgb.b -= other.b
439
+
440
+ rgb
441
+ end
442
+
443
+ # Retrieve the maxmum RGB value from the current colour as a GrayScale
444
+ # colour
445
+ def max_rgb_as_grayscale
446
+ Color::GrayScale.from_fraction([@r, @g, @b].max)
447
+ end
448
+ alias max_rgb_as_greyscale max_rgb_as_grayscale
449
+
450
+ def inspect
451
+ "RGB [#{html}]"
452
+ end
453
+ end
454
+
455
+ require 'color/rgb-colors'