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