color-tools 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: css.rb,v 1.1 2005/08/05 23:07:20 austin Exp $
10
+ #++
11
+
12
+ require 'color'
13
+
14
+ # This namespace contains some CSS colour names.
15
+ module Color::CSS
16
+ # Returns the RGB colour for name or +nil+ if the name is not valid.
17
+ def self.[](name)
18
+ @colors[name.to_s.downcase.to_sym]
19
+ end
20
+
21
+ @colors = {}
22
+ Color::RGB.constants.each do |const|
23
+ next if const == "PDF_FORMAT_STR"
24
+ next if const == "Metallic"
25
+ @colors[const.downcase.to_sym] ||= Color::RGB.const_get(const)
26
+ end
27
+ end
@@ -3,22 +3,32 @@
3
3
  #
4
4
  # Copyright 2005 Austin Ziegler
5
5
  # http://rubyforge.org/ruby-pdf/
6
+ #
7
+ # Licensed under a MIT-style licence.
8
+ #
9
+ # $Id: grayscale.rb,v 1.3 2005/08/08 02:44:17 austin Exp $
6
10
  #++
7
11
 
8
12
  # A colour object representing shades of grey. Used primarily in PDF
9
13
  # document creation.
10
14
  class Color::GrayScale
11
- # The format required to present the colour to a PDF document.
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.
12
18
  PDF_FORMAT_STR = "%.3f %s"
13
19
 
14
- # Creates a greyscale colour object from fractional values 0 .. 1.
20
+ # Creates a greyscale colour object from fractional values 0..1.
21
+ #
22
+ # Color::GreyScale.from_fraction(0.5)
15
23
  def self.from_fraction(g = 0)
16
24
  color = Color::GrayScale.new
17
25
  color.g = g
18
26
  color
19
27
  end
20
28
 
21
- # Creates a greyscale colour object from percentages 0 .. 100.
29
+ # Creates a greyscale colour object from percentages 0..100.
30
+ #
31
+ # Color::GrayScale.new(50)
22
32
  def initialize(g = 0)
23
33
  @g = g / 100.0
24
34
  end
@@ -27,18 +37,23 @@ class Color::GrayScale
27
37
  # converted to GreyScale before comparison, so the comparison between a
28
38
  # GreyScale colour and a non-GreyScale colour will be approximate and
29
39
  # based on the other colour's #to_greyscale conversion. If there is no
30
- # #to_greyscale conversion, this will raise an exception.
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.
31
43
  def ==(other)
32
44
  other = other.to_grayscale
33
- other.kind_of?(Color::GrayScale) and (@g == other.g)
45
+ other.kind_of?(Color::GrayScale) and
46
+ ((@g - other.g).abs <= 1e-4)
34
47
  end
35
48
 
36
- # Present the colour as a fill colour string for PDF.
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.
37
51
  def pdf_fill
38
52
  PDF_FORMAT_STR % [ @g, "g" ]
39
53
  end
40
54
 
41
- # Present the colour as a stroke colour string for PDF.
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.
42
57
  def pdf_stroke
43
58
  PDF_FORMAT_STR % [ @g, "G" ]
44
59
  end
@@ -50,19 +65,19 @@ class Color::GrayScale
50
65
 
51
66
  # Present the colour as an HTML/CSS colour string.
52
67
  def html
53
- gs = "%02x" % @g.to_255
68
+ gs = "%02x" % to_255
54
69
  "##{gs * 3}"
55
70
  end
56
71
 
57
72
  # Convert the greyscale colour to CMYK.
58
73
  def to_cmyk
59
74
  k = 1.0 - @g.to_f
60
- Color::CMYK.from_Fraction(0, 0, 0, k)
75
+ Color::CMYK.from_fraction(0, 0, 0, k)
61
76
  end
62
77
 
63
78
  # Convert the greyscale colour to RGB.
64
79
  def to_rgb(ignored = true)
65
- g = @g.to_255
80
+ g = to_255
66
81
  Color::RGB.new(g, g, g)
67
82
  end
68
83
 
@@ -74,12 +89,12 @@ class Color::GrayScale
74
89
  # Lightens the greyscale colour by the stated percent.
75
90
  def lighten_by(percent)
76
91
  g = [@g + (@g * (percent / 100.0)), 1.0].min
77
- Color::Grayscale.from_fraction(g)
92
+ Color::GrayScale.from_fraction(g)
78
93
  end
79
94
 
80
95
  # Darken the RGB hue by the stated percent.
81
96
  def darken_by(percent)
82
- g = [@g - (@g * (percent / 100.0)), 1.0].max
97
+ g = [@g - (@g * (percent / 100.0)), 0.0].max
83
98
  Color::GrayScale.from_fraction(g)
84
99
  end
85
100
 
@@ -94,6 +109,11 @@ class Color::GrayScale
94
109
  Color::YIQ.from_fraction(y, i, q)
95
110
  end
96
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
+
97
117
  # Returns the brightness value for this greyscale value; this is the
98
118
  # greyscale value.
99
119
  def brightness
@@ -101,5 +121,15 @@ class Color::GrayScale
101
121
  end
102
122
 
103
123
  attr_accessor :g
124
+ remove_method :g= ;
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
104
135
  end
105
- Color::GreyScale = Color::GrayScale
@@ -0,0 +1,130 @@
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: hsl.rb,v 1.2 2005/08/08 02:44:17 austin Exp $
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
+ def to_greyscale
109
+ Color::GrayScale.from_fraction(@l)
110
+ end
111
+ alias to_grayscale to_greyscale
112
+
113
+ attr_accessor :h, :s, :l
114
+ remove_method :h=, :s=, :l= ;
115
+ def h=(hh) #:nodoc:
116
+ hh = 1.0 if hh > 1
117
+ hh = 0.0 if hh < 0
118
+ @h = hh
119
+ end
120
+ def s=(ss) #:nodoc:
121
+ ss = 1.0 if ss > 1
122
+ ss = 0.0 if ss < 0
123
+ @s = ss
124
+ end
125
+ def l=(ll) #:nodoc:
126
+ ll = 1.0 if ll > 1
127
+ ll = 0.0 if ll < 0
128
+ @l = ll
129
+ end
130
+ end
@@ -3,6 +3,10 @@
3
3
  #
4
4
  # Copyright 2005 Austin Ziegler
5
5
  # http://rubyforge.org/ruby-pdf/
6
+ #
7
+ # Licensed under a MIT-style licence.
8
+ #
9
+ # $Id: palette.rb,v 1.2 2005/08/05 23:07:20 austin Exp $
6
10
  #++
7
11
 
8
12
  require 'color'
@@ -3,30 +3,50 @@
3
3
  #
4
4
  # Copyright 2005 Austin Ziegler
5
5
  # http://rubyforge.org/ruby-pdf/
6
+ #
7
+ # Licensed under a MIT-style licence.
8
+ #
9
+ # $Id: gimp.rb,v 1.3 2005/08/08 02:44:17 austin Exp $
6
10
  #++
7
11
 
8
12
  require 'color/palette'
9
13
 
14
+ # A class that can read a GIMP (GNU Image Manipulation Program) palette
15
+ # file and provide a Hash-like interface to the contents. GIMP colour
16
+ # palettes are RGB values only.
17
+ #
18
+ # Because two or more entries in a GIMP palette may have the same name,
19
+ # all named entries are returned as an array.
20
+ #
21
+ # pal = Color::Palette::Gimp.from_file(my_gimp_palette)
22
+ # pal[0] => Color::RGB<...>
23
+ # pal["white"] => [ Color::RGB<...> ]
24
+ # pal["unknown"] => [ Color::RGB<...>, Color::RGB<...>, ... ]
25
+ #
26
+ # GIMP Palettes are always indexable by insertion order (an integer key).
10
27
  class Color::Palette::Gimp
11
28
  include Enumerable
12
29
 
13
30
  class << self
31
+ # Create a GIMP palette object from the named file.
14
32
  def from_file(filename)
15
33
  File.open(filename, "rb") { |io| Color::Palette::Gimp.from_io(io) }
16
34
  end
17
35
 
36
+ # Create a GIMP palette object from the provided IO.
18
37
  def from_io(io)
19
38
  Color::Palette::Gimp.new(io.read)
20
39
  end
21
40
  end
22
41
 
42
+ # Create a new GIMP palette.
23
43
  def initialize(palette)
24
- @colors = {}
44
+ @colors = []
45
+ @names = {}
25
46
  @valid = false
26
47
  @name = "(unnamed)"
27
48
 
28
49
  index = 0
29
- collision = {}
30
50
 
31
51
  palette.split($/).each do |line|
32
52
  line.chomp!
@@ -47,26 +67,41 @@ class Color::Palette::Gimp
47
67
 
48
68
  line.gsub!(/^\s+/, '')
49
69
  data = line.split(/\s+/, 4)
50
- name = data.pop
70
+ name = data.pop.strip
51
71
  data.map! { |el| el.to_i }
52
72
 
53
- @colors[index] = Color::RGB.new(*data)
73
+ color = Color::RGB.new(*data)
54
74
 
55
- if @colors.has_key?(name)
56
- collision[name] = true
57
- else
58
- @colors[name] = @colors[index]
59
- end
60
- end
75
+ @colors[index] = color
76
+ @names[name] ||= []
77
+ @names[name] << color
61
78
 
62
- collision.each_key { |key| @colors.delete_at(key) }
79
+ index += 1
80
+ end
63
81
  end
64
82
 
65
83
  def [](key)
66
- @colors[key]
84
+ if key.kind_of?(Numeric)
85
+ @colors[key]
86
+ else
87
+ @names[key]
88
+ end
67
89
  end
68
90
 
91
+ # Loops through each colour.
69
92
  def each
70
93
  @colors.each { |el| yield el }
71
94
  end
95
+
96
+ # Loops through each named colour set.
97
+ def each_name #:yields color_name, color_set:#
98
+ @names.each { |color_name, color_set| yield color_name, color_set }
99
+ end
100
+
101
+ # Returns true if this is believed to be a valid GIMP palette.
102
+ def valid?
103
+ @valid
104
+ end
105
+
106
+ attr_reader :name
72
107
  end
@@ -3,6 +3,10 @@
3
3
  #
4
4
  # Copyright 2005 Austin Ziegler
5
5
  # http://rubyforge.org/ruby-pdf/
6
+ #
7
+ # Licensed under a MIT-style licence.
8
+ #
9
+ # $Id: monocontrast.rb,v 1.3 2005/08/08 02:44:17 austin Exp $
6
10
  #++
7
11
 
8
12
  require 'color/palette'
@@ -26,7 +30,7 @@ class Color::Palette::MonoContrast
26
30
  # 0:: The starting colour.
27
31
  # +1..+5:: Lighter colours.
28
32
  # -1..-5:: Darker colours.
29
- attr_accessor :background
33
+ attr_reader :background
30
34
  # Hash of CSS foreground colour values.
31
35
  #
32
36
  # This is always 11 values:
@@ -34,30 +38,56 @@ class Color::Palette::MonoContrast
34
38
  # 0:: The starting colour.
35
39
  # +1..+5:: Lighter colours.
36
40
  # -1..-5:: Darker colours.
37
- attr_accessor :foreground
41
+ attr_reader :foreground
42
+
43
+ DEFAULT_MINIMUM_BRIGHTNESS_DIFF = (125.0 / 255.0)
38
44
 
39
45
  # The minimum brightness difference between the background and the
40
- # foreground. Setting this value will regenerate the palette based on
41
- # the base colours. The default value for this is 125 / 255.0.
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.
42
50
  attr_accessor :minimum_brightness_diff
51
+ remove_method :minimum_brightness_diff= ;
43
52
  def minimum_brightness_diff=(bd) #:nodoc:
44
- @minimum_brightness_diff = bd
53
+ if bd.nil?
54
+ @minimum_brightness_diff = DEFAULT_MINIMUM_BRIGHTNESS_DIFF
55
+ elsif bd > 1.0
56
+ @minimum_brightness_diff = 1.0
57
+ elsif bd < 0.0
58
+ @minimum_brightness_diff = 0.0
59
+ else
60
+ @minimum_brightness_diff = bd
61
+ end
62
+
45
63
  regenerate(@background[0], @foreground[0])
46
64
  end
47
65
 
66
+ DEFAULT_MINIMUM_COLOR_DIFF = (500.0 / 255.0)
67
+
48
68
  # The minimum colour difference between the background and the
49
- # foreground. Setting this value will regenerate the palette based on
50
- # the base colours.
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.
51
72
  attr_accessor :minimum_color_diff
73
+ remove_method :minimum_color_diff= ;
52
74
  def minimum_color_diff=(cd) #:noco:
53
- @minimum_color_diff = bd
75
+ if cd.nil?
76
+ @minimum_color_diff = DEFAULT_MINIMUM_COLOR_DIFF
77
+ elsif cd > 3.0
78
+ @minimum_color_diff = 3.0
79
+ elsif cd < 0.0
80
+ @minimum_color_diff = 0.0
81
+ else
82
+ @minimum_color_diff = cd
83
+ end
54
84
  regenerate(@background[0], @foreground[0])
55
85
  end
56
86
 
57
87
  # Generate the initial palette.
58
88
  def initialize(background, foreground = nil)
59
- @minimum_brightness_diff = 125 / 255.0
60
- @minimum_color_diff = 500 / 765.0
89
+ @minimum_brightness_diff = DEFAULT_MINIMUM_BRIGHTNESS_DIFF
90
+ @minimum_color_diff = DEFAULT_MINIMUM_COLOR_DIFF
61
91
 
62
92
  regenerate(background, foreground)
63
93
  end
@@ -140,7 +170,7 @@ class Color::Palette::MonoContrast
140
170
  # Returns the contrast between to colours, a decimal value between 0 and
141
171
  # 3. W3C accessibility guidelines for colour
142
172
  # contrast[http://www.w3.org/TR/AERT#color-contrast] suggest that this
143
- # value be at least approximately 1.96 (500 / 765.0) for proper contrast.
173
+ # value be at least approximately 1.96 (500 / 255.0) for proper contrast.
144
174
  def color_diff(c1, c2)
145
175
  r = (c1.r - c2.r).abs
146
176
  g = (c1.g - c2.g).abs