ripta-color-tools 1.4.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 +7 -0
- data/Changelog +55 -0
- data/Install +18 -0
- data/README.rdoc +82 -0
- data/Rakefile +123 -0
- data/lib/color.rb +78 -0
- data/lib/color/cmyk.rb +185 -0
- data/lib/color/css.rb +27 -0
- data/lib/color/grayscale.rb +135 -0
- data/lib/color/hsl.rb +134 -0
- data/lib/color/palette.rb +18 -0
- data/lib/color/palette/gimp.rb +105 -0
- data/lib/color/palette/monocontrast.rb +178 -0
- data/lib/color/rgb-colors.rb +189 -0
- data/lib/color/rgb.rb +315 -0
- data/lib/color/rgb/metallic.rb +28 -0
- data/lib/color/yiq.rb +80 -0
- data/metaconfig +13 -0
- data/pre-setup.rb +55 -0
- data/setup.rb +1366 -0
- data/tests/test_cmyk.rb +116 -0
- data/tests/test_css.rb +28 -0
- data/tests/test_gimp.rb +79 -0
- data/tests/test_grayscale.rb +87 -0
- data/tests/test_hsl.rb +93 -0
- data/tests/test_monocontrast.rb +145 -0
- data/tests/test_rgb.rb +160 -0
- data/tests/test_yiq.rb +81 -0
- data/tests/testall.rb +20 -0
- metadata +84 -0
data/lib/color/css.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#--
|
2
|
+
# Colour management with Ruby.
|
3
|
+
#
|
4
|
+
# Copyright 2005 Austin Ziegler
|
5
|
+
# http://rubyforge.org/ruby-pdf/
|
6
|
+
#
|
7
|
+
# Licensed under a MIT-style licence.
|
8
|
+
#
|
9
|
+
# $Id$
|
10
|
+
#++
|
11
|
+
|
12
|
+
# This namespace contains some CSS colour names.
|
13
|
+
module Color::CSS
|
14
|
+
|
15
|
+
# Returns the RGB colour for name or +nil+ if the name is not valid.
|
16
|
+
def self.[](name)
|
17
|
+
@colors[name.to_s.downcase.to_sym]
|
18
|
+
end
|
19
|
+
|
20
|
+
@colors = {}
|
21
|
+
Color::RGB.constants.each do |const|
|
22
|
+
next if const == "PDF_FORMAT_STR"
|
23
|
+
next if const == "Metallic"
|
24
|
+
@colors[const.downcase.to_sym] ||= Color::RGB.const_get(const)
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
#--
|
2
|
+
# Colour management with Ruby.
|
3
|
+
#
|
4
|
+
# Copyright 2005 Austin Ziegler
|
5
|
+
# http://rubyforge.org/ruby-pdf/
|
6
|
+
#
|
7
|
+
# Licensed under a MIT-style licence.
|
8
|
+
#
|
9
|
+
# $Id$
|
10
|
+
#++
|
11
|
+
|
12
|
+
# A colour object representing shades of grey. Used primarily in PDF
|
13
|
+
# document creation.
|
14
|
+
class Color::GrayScale
|
15
|
+
# The format of a DeviceGrey colour for PDF. In color-tools 2.0 this
|
16
|
+
# will be removed from this package and added back as a modification by
|
17
|
+
# the PDF::Writer package.
|
18
|
+
PDF_FORMAT_STR = "%.3f %s"
|
19
|
+
|
20
|
+
# Creates a greyscale colour object from fractional values 0..1.
|
21
|
+
#
|
22
|
+
# Color::GreyScale.from_fraction(0.5)
|
23
|
+
def self.from_fraction(g = 0)
|
24
|
+
color = Color::GrayScale.new
|
25
|
+
color.g = g
|
26
|
+
color
|
27
|
+
end
|
28
|
+
|
29
|
+
# Creates a greyscale colour object from percentages 0..100.
|
30
|
+
#
|
31
|
+
# Color::GrayScale.new(50)
|
32
|
+
def initialize(g = 0)
|
33
|
+
@g = g / 100.0
|
34
|
+
end
|
35
|
+
|
36
|
+
# Compares the other colour to this one. The other colour will be
|
37
|
+
# converted to GreyScale before comparison, so the comparison between a
|
38
|
+
# GreyScale colour and a non-GreyScale colour will be approximate and
|
39
|
+
# based on the other colour's #to_greyscale conversion. If there is no
|
40
|
+
# #to_greyscale conversion, this will raise an exception. This will
|
41
|
+
# report that two GreyScale values are equivalent if they are within
|
42
|
+
# 1e-4 (0.0001) of each other.
|
43
|
+
def ==(other)
|
44
|
+
other = other.to_grayscale
|
45
|
+
other.kind_of?(Color::GrayScale) and
|
46
|
+
((@g - other.g).abs <= 1e-4)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Present the colour as a DeviceGrey fill colour string for PDF. This
|
50
|
+
# will be removed from the default package in color-tools 2.0.
|
51
|
+
def pdf_fill
|
52
|
+
PDF_FORMAT_STR % [ @g, "g" ]
|
53
|
+
end
|
54
|
+
|
55
|
+
# Present the colour as a DeviceGrey stroke colour string for PDF. This
|
56
|
+
# will be removed from the default package in color-tools 2.0.
|
57
|
+
def pdf_stroke
|
58
|
+
PDF_FORMAT_STR % [ @g, "G" ]
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_255
|
62
|
+
[(@g * 255).round, 255].min
|
63
|
+
end
|
64
|
+
private :to_255
|
65
|
+
|
66
|
+
# Present the colour as an HTML/CSS colour string.
|
67
|
+
def html
|
68
|
+
gs = "%02x" % to_255
|
69
|
+
"##{gs * 3}"
|
70
|
+
end
|
71
|
+
|
72
|
+
# Convert the greyscale colour to CMYK.
|
73
|
+
def to_cmyk
|
74
|
+
k = 1.0 - @g.to_f
|
75
|
+
Color::CMYK.from_fraction(0, 0, 0, k)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Convert the greyscale colour to RGB.
|
79
|
+
def to_rgb(ignored = true)
|
80
|
+
g = to_255
|
81
|
+
Color::RGB.new(g, g, g)
|
82
|
+
end
|
83
|
+
|
84
|
+
def to_grayscale
|
85
|
+
self
|
86
|
+
end
|
87
|
+
alias to_greyscale to_grayscale
|
88
|
+
|
89
|
+
# Lightens the greyscale colour by the stated percent.
|
90
|
+
def lighten_by(percent)
|
91
|
+
g = [@g + (@g * (percent / 100.0)), 1.0].min
|
92
|
+
Color::GrayScale.from_fraction(g)
|
93
|
+
end
|
94
|
+
|
95
|
+
# Darken the RGB hue by the stated percent.
|
96
|
+
def darken_by(percent)
|
97
|
+
g = [@g - (@g * (percent / 100.0)), 0.0].max
|
98
|
+
Color::GrayScale.from_fraction(g)
|
99
|
+
end
|
100
|
+
|
101
|
+
# Returns the YIQ (NTSC) colour encoding of the greyscale value. This
|
102
|
+
# is an approximation, as the values for I and Q are calculated by
|
103
|
+
# treating the greyscale value as an RGB value. The Y (intensity or
|
104
|
+
# brightness) value is the same as the greyscale value.
|
105
|
+
def to_yiq
|
106
|
+
y = @g
|
107
|
+
i = (@g * 0.596) + (@g * -0.275) + (@g * -0.321)
|
108
|
+
q = (@g * 0.212) + (@g * -0.523) + (@g * 0.311)
|
109
|
+
Color::YIQ.from_fraction(y, i, q)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Returns the HSL colour encoding of the greyscale value.
|
113
|
+
def to_hsl
|
114
|
+
Color::HSL.from_fraction(0, 0, @g)
|
115
|
+
end
|
116
|
+
|
117
|
+
# Returns the brightness value for this greyscale value; this is the
|
118
|
+
# greyscale value.
|
119
|
+
def brightness
|
120
|
+
@g
|
121
|
+
end
|
122
|
+
|
123
|
+
attr_reader :g
|
124
|
+
|
125
|
+
def g=(gg) #:nodoc:
|
126
|
+
gg = 1.0 if gg > 1
|
127
|
+
gg = 0.0 if gg < 0
|
128
|
+
@g = gg
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
module Color
|
133
|
+
# A synonym for Color::GrayScale.
|
134
|
+
GreyScale = GrayScale
|
135
|
+
end
|
data/lib/color/hsl.rb
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
#--
|
2
|
+
# Colour management with Ruby.
|
3
|
+
#
|
4
|
+
# Copyright 2005 Austin Ziegler
|
5
|
+
# http://rubyforge.org/ruby-pdf/
|
6
|
+
#
|
7
|
+
# Licensed under a MIT-style licence.
|
8
|
+
#
|
9
|
+
# $Id$
|
10
|
+
#++
|
11
|
+
|
12
|
+
# An HSL colour object. Internally, the hue (#h), saturation (#s), and
|
13
|
+
# luminosity (#l) values are dealt with as fractional values in the range
|
14
|
+
# 0..1.
|
15
|
+
class Color::HSL
|
16
|
+
class << self
|
17
|
+
# Creates an HSL colour object from fractional values 0..1.
|
18
|
+
def from_fraction(h = 0.0, s = 0.0, l = 0.0)
|
19
|
+
colour = Color::HSL.new
|
20
|
+
colour.h = h
|
21
|
+
colour.s = s
|
22
|
+
colour.l = l
|
23
|
+
colour
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Compares the other colour to this one. The other colour will be
|
28
|
+
# converted to HSL before comparison, so the comparison between a HSL
|
29
|
+
# colour and a non-HSL colour will be approximate and based on the other
|
30
|
+
# colour's #to_hsl conversion. If there is no #to_hsl conversion, this
|
31
|
+
# will raise an exception. This will report that two HSL values are
|
32
|
+
# equivalent if all component values are within 1e-4 (0.0001) of each
|
33
|
+
# other.
|
34
|
+
def ==(other)
|
35
|
+
other = other.to_hsl
|
36
|
+
other.kind_of?(Color::HSL) and
|
37
|
+
((@h - other.h).abs <= 1e-4) and
|
38
|
+
((@s - other.s).abs <= 1e-4) and
|
39
|
+
((@l - other.l).abs <= 1e-4)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Creates an HSL colour object from the standard values of degrees and
|
43
|
+
# percentages (e.g., 145�, 30%, 50%).
|
44
|
+
def initialize(h = 0, s = 0, l = 0)
|
45
|
+
@h = h / 360.0
|
46
|
+
@s = s / 100.0
|
47
|
+
@l = l / 100.0
|
48
|
+
end
|
49
|
+
|
50
|
+
# Present the colour as an HTML/CSS colour string.
|
51
|
+
def html
|
52
|
+
to_rgb.html
|
53
|
+
end
|
54
|
+
|
55
|
+
# Converting to HSL as adapted from Foley and Van-Dam from
|
56
|
+
# http://www.bobpowell.net/RGBHSB.htm.
|
57
|
+
def to_rgb(ignored = nil)
|
58
|
+
# If luminosity is zero, the colour is always black.
|
59
|
+
return Color::RGB.new if @l == 0
|
60
|
+
# If luminosity is one, the colour is always white.
|
61
|
+
return Color::RGB.new(0xff, 0xff, 0xff) if @l == 1
|
62
|
+
# If saturation is zero, the colour is always a greyscale colour.
|
63
|
+
return Color::RGB.new(@l, @l, @l) if @s <= 1e-5
|
64
|
+
|
65
|
+
if (@l - 0.5) < 1e-5
|
66
|
+
tmp2 = @l * (1.0 + @s.to_f)
|
67
|
+
else
|
68
|
+
tmp2 = @l + @s - (@l * @s.to_f)
|
69
|
+
end
|
70
|
+
tmp1 = 2.0 * @l - tmp2
|
71
|
+
|
72
|
+
t3 = [ @h + 1.0 / 3.0, @h, @h - 1.0 / 3.0 ]
|
73
|
+
t3 = t3.map { |tmp3|
|
74
|
+
tmp3 += 1.0 if tmp3 < 1e-5
|
75
|
+
tmp3 -= 1.0 if (tmp3 - 1.0) > 1e-5
|
76
|
+
tmp3
|
77
|
+
}
|
78
|
+
|
79
|
+
rgb = t3.map do |tmp3|
|
80
|
+
if ((6.0 * tmp3) - 1.0) < 1e-5
|
81
|
+
tmp1 + ((tmp2 - tmp1) * tmp3 * 6.0)
|
82
|
+
elsif ((2.0 * tmp3) - 1.0) < 1e-5
|
83
|
+
tmp2
|
84
|
+
elsif ((3.0 * tmp3) - 2.0) < 1e-5
|
85
|
+
tmp1 + (tmp2 - tmp1) * ((2 / 3.0) - tmp3) * 6.0
|
86
|
+
else
|
87
|
+
tmp1
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
Color::RGB.from_fraction(*rgb)
|
92
|
+
end
|
93
|
+
|
94
|
+
# Converts to RGB then YIQ.
|
95
|
+
def to_yiq
|
96
|
+
to_rgb.to_yiq
|
97
|
+
end
|
98
|
+
|
99
|
+
# Converts to RGB then CMYK.
|
100
|
+
def to_cmyk
|
101
|
+
to_rgb.to_cmyk
|
102
|
+
end
|
103
|
+
|
104
|
+
# Returns the luminosity (#l) of the colour.
|
105
|
+
def brightness
|
106
|
+
@l
|
107
|
+
end
|
108
|
+
|
109
|
+
def to_greyscale
|
110
|
+
Color::GrayScale.from_fraction(@l)
|
111
|
+
end
|
112
|
+
|
113
|
+
alias to_grayscale to_greyscale
|
114
|
+
|
115
|
+
attr_reader :h, :s, :l
|
116
|
+
|
117
|
+
def h=(hh) #:nodoc:
|
118
|
+
hh = 1.0 if hh > 1
|
119
|
+
hh = 0.0 if hh < 0
|
120
|
+
@h = hh
|
121
|
+
end
|
122
|
+
|
123
|
+
def s=(ss) #:nodoc:
|
124
|
+
ss = 1.0 if ss > 1
|
125
|
+
ss = 0.0 if ss < 0
|
126
|
+
@s = ss
|
127
|
+
end
|
128
|
+
|
129
|
+
def l=(ll) #:nodoc:
|
130
|
+
ll = 1.0 if ll > 1
|
131
|
+
ll = 0.0 if ll < 0
|
132
|
+
@l = ll
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#--
|
2
|
+
# Colour management with Ruby.
|
3
|
+
#
|
4
|
+
# Copyright 2005 Austin Ziegler
|
5
|
+
# http://rubyforge.org/ruby-pdf/
|
6
|
+
#
|
7
|
+
# Licensed under a MIT-style licence.
|
8
|
+
#
|
9
|
+
# $Id$
|
10
|
+
#++
|
11
|
+
module Color
|
12
|
+
module Palette
|
13
|
+
|
14
|
+
autoload :Gimp, "color/palette/gimp"
|
15
|
+
autoload :MonoContrast, "color/palette/monocontrast"
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
#--
|
2
|
+
# Colour management with Ruby.
|
3
|
+
#
|
4
|
+
# Copyright 2005 Austin Ziegler
|
5
|
+
# http://rubyforge.org/ruby-pdf/
|
6
|
+
#
|
7
|
+
# Licensed under a MIT-style licence.
|
8
|
+
#
|
9
|
+
# $Id$
|
10
|
+
#++
|
11
|
+
|
12
|
+
# A class that can read a GIMP (GNU Image Manipulation Program) palette
|
13
|
+
# file and provide a Hash-like interface to the contents. GIMP colour
|
14
|
+
# palettes are RGB values only.
|
15
|
+
#
|
16
|
+
# Because two or more entries in a GIMP palette may have the same name,
|
17
|
+
# all named entries are returned as an array.
|
18
|
+
#
|
19
|
+
# pal = Color::Palette::Gimp.from_file(my_gimp_palette)
|
20
|
+
# pal[0] => Color::RGB<...>
|
21
|
+
# pal["white"] => [ Color::RGB<...> ]
|
22
|
+
# pal["unknown"] => [ Color::RGB<...>, Color::RGB<...>, ... ]
|
23
|
+
#
|
24
|
+
# GIMP Palettes are always indexable by insertion order (an integer key).
|
25
|
+
class Color::Palette::Gimp
|
26
|
+
include Enumerable
|
27
|
+
|
28
|
+
class << self
|
29
|
+
# Create a GIMP palette object from the named file.
|
30
|
+
def from_file(filename)
|
31
|
+
File.open(filename, "rb") { |io| Color::Palette::Gimp.from_io(io) }
|
32
|
+
end
|
33
|
+
|
34
|
+
# Create a GIMP palette object from the provided IO.
|
35
|
+
def from_io(io)
|
36
|
+
Color::Palette::Gimp.new(io.read)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Create a new GIMP palette.
|
41
|
+
def initialize(palette)
|
42
|
+
@colors = []
|
43
|
+
@names = {}
|
44
|
+
@valid = false
|
45
|
+
@name = "(unnamed)"
|
46
|
+
|
47
|
+
index = 0
|
48
|
+
|
49
|
+
palette.split($/).each do |line|
|
50
|
+
line.chomp!
|
51
|
+
line.gsub!(/\s*#.*\Z/, '')
|
52
|
+
|
53
|
+
next if line.empty?
|
54
|
+
|
55
|
+
if line =~ /\AGIMP Palette\Z/
|
56
|
+
@valid = true
|
57
|
+
next
|
58
|
+
end
|
59
|
+
|
60
|
+
info = /(\w+):\s(.*$)/.match(line)
|
61
|
+
if info
|
62
|
+
@name = info.captures[1] if info.captures[0] =~ /name/i
|
63
|
+
next
|
64
|
+
end
|
65
|
+
|
66
|
+
line.gsub!(/^\s+/, '')
|
67
|
+
data = line.split(/\s+/, 4)
|
68
|
+
name = data.pop.strip
|
69
|
+
data.map! { |el| el.to_i }
|
70
|
+
|
71
|
+
color = Color::RGB.new(*data)
|
72
|
+
|
73
|
+
@colors[index] = color
|
74
|
+
@names[name] ||= []
|
75
|
+
@names[name] << color
|
76
|
+
|
77
|
+
index += 1
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def [](key)
|
82
|
+
if key.kind_of?(Numeric)
|
83
|
+
@colors[key]
|
84
|
+
else
|
85
|
+
@names[key]
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Loops through each colour.
|
90
|
+
def each
|
91
|
+
@colors.each { |el| yield el }
|
92
|
+
end
|
93
|
+
|
94
|
+
# Loops through each named colour set.
|
95
|
+
def each_name #:yields color_name, color_set:#
|
96
|
+
@names.each { |color_name, color_set| yield color_name, color_set }
|
97
|
+
end
|
98
|
+
|
99
|
+
# Returns true if this is believed to be a valid GIMP palette.
|
100
|
+
def valid?
|
101
|
+
@valid
|
102
|
+
end
|
103
|
+
|
104
|
+
attr_reader :name
|
105
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
#--
|
2
|
+
# Colour management with Ruby.
|
3
|
+
#
|
4
|
+
# Copyright 2005 Austin Ziegler
|
5
|
+
# http://rubyforge.org/ruby-pdf/
|
6
|
+
#
|
7
|
+
# Licensed under a MIT-style licence.
|
8
|
+
#
|
9
|
+
# $Id$
|
10
|
+
#++
|
11
|
+
|
12
|
+
# Generates a monochromatic constrasting colour palette for background and
|
13
|
+
# foreground. What does this mean?
|
14
|
+
#
|
15
|
+
# Monochromatic: A single colour is used to generate the base palette, and
|
16
|
+
# this colour is lightened five times and darkened five times to provide
|
17
|
+
# eleven distinct colours.
|
18
|
+
#
|
19
|
+
# Contrasting: The foreground is also generated as a monochromatic colour
|
20
|
+
# palettte; however, all generated colours are tested to see that they are
|
21
|
+
# appropriately contrasting to ensure maximum readability of the
|
22
|
+
# foreground against the background.
|
23
|
+
class Color::Palette::MonoContrast
|
24
|
+
# Hash of CSS background colour values.
|
25
|
+
#
|
26
|
+
# This is always 11 values:
|
27
|
+
#
|
28
|
+
# 0:: The starting colour.
|
29
|
+
# +1..+5:: Lighter colours.
|
30
|
+
# -1..-5:: Darker colours.
|
31
|
+
attr_reader :background
|
32
|
+
# Hash of CSS foreground colour values.
|
33
|
+
#
|
34
|
+
# This is always 11 values:
|
35
|
+
#
|
36
|
+
# 0:: The starting colour.
|
37
|
+
# +1..+5:: Lighter colours.
|
38
|
+
# -1..-5:: Darker colours.
|
39
|
+
attr_reader :foreground
|
40
|
+
|
41
|
+
DEFAULT_MINIMUM_BRIGHTNESS_DIFF = (125.0 / 255.0)
|
42
|
+
|
43
|
+
attr_reader :minimum_brightness_diff
|
44
|
+
|
45
|
+
# The minimum brightness difference between the background and the
|
46
|
+
# foreground, and must be between 0..1. Setting this value will
|
47
|
+
# regenerate the palette based on the base colours. The default value
|
48
|
+
# for this is 125 / 255.0. If this value is set to +nil+, it will be
|
49
|
+
# restored to the default.
|
50
|
+
def minimum_brightness_diff=(bd) #:nodoc:
|
51
|
+
if bd.nil?
|
52
|
+
@minimum_brightness_diff = DEFAULT_MINIMUM_BRIGHTNESS_DIFF
|
53
|
+
elsif bd > 1.0
|
54
|
+
@minimum_brightness_diff = 1.0
|
55
|
+
elsif bd < 0.0
|
56
|
+
@minimum_brightness_diff = 0.0
|
57
|
+
else
|
58
|
+
@minimum_brightness_diff = bd
|
59
|
+
end
|
60
|
+
|
61
|
+
regenerate(@background[0], @foreground[0])
|
62
|
+
end
|
63
|
+
|
64
|
+
DEFAULT_MINIMUM_COLOR_DIFF = (500.0 / 255.0)
|
65
|
+
|
66
|
+
attr_reader :minimum_color_diff
|
67
|
+
|
68
|
+
# The minimum colour difference between the background and the
|
69
|
+
# foreground, and must be between 0..3. Setting this value will
|
70
|
+
# regenerate the palette based on the base colours. The default value
|
71
|
+
# for this is 500 / 255.0.
|
72
|
+
def minimum_color_diff=(cd) #:noco:
|
73
|
+
if cd.nil?
|
74
|
+
@minimum_color_diff = DEFAULT_MINIMUM_COLOR_DIFF
|
75
|
+
elsif cd > 3.0
|
76
|
+
@minimum_color_diff = 3.0
|
77
|
+
elsif cd < 0.0
|
78
|
+
@minimum_color_diff = 0.0
|
79
|
+
else
|
80
|
+
@minimum_color_diff = cd
|
81
|
+
end
|
82
|
+
regenerate(@background[0], @foreground[0])
|
83
|
+
end
|
84
|
+
|
85
|
+
# Generate the initial palette.
|
86
|
+
def initialize(background, foreground = nil)
|
87
|
+
@minimum_brightness_diff = DEFAULT_MINIMUM_BRIGHTNESS_DIFF
|
88
|
+
@minimum_color_diff = DEFAULT_MINIMUM_COLOR_DIFF
|
89
|
+
|
90
|
+
regenerate(background, foreground)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Generate the colour palettes.
|
94
|
+
def regenerate(background, foreground = nil)
|
95
|
+
foreground ||= background
|
96
|
+
background = background.to_rgb
|
97
|
+
foreground = foreground.to_rgb
|
98
|
+
|
99
|
+
@background = {}
|
100
|
+
@foreground = {}
|
101
|
+
|
102
|
+
@background[-5] = background.darken_by(10)
|
103
|
+
@background[-4] = background.darken_by(25)
|
104
|
+
@background[-3] = background.darken_by(50)
|
105
|
+
@background[-2] = background.darken_by(75)
|
106
|
+
@background[-1] = background.darken_by(85)
|
107
|
+
@background[ 0] = background
|
108
|
+
@background[+1] = background.lighten_by(85)
|
109
|
+
@background[+2] = background.lighten_by(75)
|
110
|
+
@background[+3] = background.lighten_by(50)
|
111
|
+
@background[+4] = background.lighten_by(25)
|
112
|
+
@background[+5] = background.lighten_by(10)
|
113
|
+
|
114
|
+
@foreground[-5] = calculate_foreground(@background[-5], foreground)
|
115
|
+
@foreground[-4] = calculate_foreground(@background[-4], foreground)
|
116
|
+
@foreground[-3] = calculate_foreground(@background[-3], foreground)
|
117
|
+
@foreground[-2] = calculate_foreground(@background[-2], foreground)
|
118
|
+
@foreground[-1] = calculate_foreground(@background[-1], foreground)
|
119
|
+
@foreground[ 0] = calculate_foreground(@background[ 0], foreground)
|
120
|
+
@foreground[+1] = calculate_foreground(@background[+1], foreground)
|
121
|
+
@foreground[+2] = calculate_foreground(@background[+2], foreground)
|
122
|
+
@foreground[+3] = calculate_foreground(@background[+3], foreground)
|
123
|
+
@foreground[+4] = calculate_foreground(@background[+4], foreground)
|
124
|
+
@foreground[+5] = calculate_foreground(@background[+5], foreground)
|
125
|
+
end
|
126
|
+
|
127
|
+
# Given a background colour and a foreground colour, modifies the
|
128
|
+
# foreground colour so that it will have enough contrast to be seen
|
129
|
+
# against the background colour.
|
130
|
+
#
|
131
|
+
# Uses #mininum_brightness_diff and #minimum_color_diff.
|
132
|
+
def calculate_foreground(background, foreground)
|
133
|
+
nfg = nil
|
134
|
+
# Loop through brighter and darker versions of the foreground color.
|
135
|
+
# The numbers here represent the amount of foreground color to mix
|
136
|
+
# with black and white.
|
137
|
+
[100, 75, 50, 25, 0].each do |percent|
|
138
|
+
dfg = foreground.darken_by(percent)
|
139
|
+
lfg = foreground.lighten_by(percent)
|
140
|
+
|
141
|
+
dbd = brightness_diff(background, dfg)
|
142
|
+
lbd = brightness_diff(background, lfg)
|
143
|
+
|
144
|
+
if lbd > dbd
|
145
|
+
nfg = lfg
|
146
|
+
nbd = lbd
|
147
|
+
else
|
148
|
+
nfg = dfg
|
149
|
+
nbd = dbd
|
150
|
+
end
|
151
|
+
|
152
|
+
ncd = color_diff(background, nfg)
|
153
|
+
|
154
|
+
break if nbd >= @minimum_brightness_diff and ncd >= @minimum_color_diff
|
155
|
+
end
|
156
|
+
nfg
|
157
|
+
end
|
158
|
+
|
159
|
+
# Returns the absolute difference between the brightness levels of two
|
160
|
+
# colours. This will be a decimal value between 0 and 1. W3C
|
161
|
+
# accessibility guidelines for colour
|
162
|
+
# contrast[http://www.w3.org/TR/AERT#color-contrast] suggest that this
|
163
|
+
# value be at least approximately 0.49 (125 / 255.0) for proper contrast.
|
164
|
+
def brightness_diff(c1, c2)
|
165
|
+
(c1.brightness - c2.brightness).abs
|
166
|
+
end
|
167
|
+
|
168
|
+
# Returns the contrast between to colours, a decimal value between 0 and
|
169
|
+
# 3. W3C accessibility guidelines for colour
|
170
|
+
# contrast[http://www.w3.org/TR/AERT#color-contrast] suggest that this
|
171
|
+
# value be at least approximately 1.96 (500 / 255.0) for proper contrast.
|
172
|
+
def color_diff(c1, c2)
|
173
|
+
r = (c1.r - c2.r).abs
|
174
|
+
g = (c1.g - c2.g).abs
|
175
|
+
b = (c1.b - c2.b).abs
|
176
|
+
r + g + b
|
177
|
+
end
|
178
|
+
end
|