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.
- data/History.txt +91 -0
- data/Install.txt +20 -0
- data/Licence.txt +29 -0
- data/Manifest.txt +31 -0
- data/Rakefile +116 -0
- data/Readme.txt +33 -0
- data/lib/color.rb +147 -0
- data/lib/color/cmyk.rb +281 -0
- data/lib/color/css.rb +30 -0
- data/lib/color/grayscale.rb +214 -0
- data/lib/color/hsl.rb +223 -0
- data/lib/color/palette.rb +18 -0
- data/lib/color/palette/adobecolor.rb +274 -0
- data/lib/color/palette/gimp.rb +118 -0
- data/lib/color/palette/monocontrast.rb +182 -0
- data/lib/color/rgb-colors.rb +357 -0
- data/lib/color/rgb.rb +455 -0
- data/lib/color/rgb/metallic.rb +45 -0
- data/lib/color/yiq.rb +86 -0
- data/setup.rb +1585 -0
- data/test/test_adobecolor.rb +421 -0
- data/test/test_all.rb +25 -0
- data/test/test_cmyk.rb +130 -0
- data/test/test_color.rb +134 -0
- data/test/test_css.rb +31 -0
- data/test/test_gimp.rb +103 -0
- data/test/test_grayscale.rb +123 -0
- data/test/test_hsl.rb +155 -0
- data/test/test_monocontrast.rb +144 -0
- data/test/test_rgb.rb +346 -0
- data/test/test_yiq.rb +75 -0
- metadata +109 -0
data/lib/color/rgb.rb
ADDED
@@ -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'
|