color 1.4.1 → 1.8

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -1,116 +1,75 @@
1
- #! /usr/bin/env rake
2
- #--
3
- # Color
4
- # Colour Management with Ruby
5
- # http://rubyforge.org/projects/color
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 - 2010 Austin Ziegler and Matt Lyon
11
- #++
1
+ # -*- ruby -*-
12
2
 
13
3
  require 'rubygems'
14
4
  require 'hoe'
15
-
16
- $LOAD_PATH.unshift('lib')
17
-
18
- require 'color'
19
-
20
- PKG_NAME = 'color'
21
- PKG_VERSION = Color::COLOR_VERSION
22
- PKG_DIST = "#{PKG_NAME}-#{PKG_VERSION}"
23
- PKG_TAR = "pkg/#{PKG_DIST}.tar.gz"
24
- MANIFEST = File.read("Manifest.txt").split
25
-
26
- Hoe.spec PKG_NAME do
27
- self.version = PKG_VERSION
28
-
29
- # self.rubyforge_name = PKG_NAME
30
-
31
- developer "Austin Ziegler", "austin@rubyforge.org"
32
- developer "Matt Lyon", "matt@postsomnia.com"
33
-
34
- self.url = %W(http://color.rubyforge.org/ http://github.com/halostatue/color)
35
-
36
- self.summary = "Colour management with Ruby"
37
- self.changes = paragraphs_of("History.txt", 0..1).join("\n\n")
38
- self.description = paragraphs_of("README.txt", 1..1).join("\n\n")
39
-
40
- extra_dev_deps << [ "archive-tar-minitar", "~>0.5.1" ]
41
- clean_globs << "coverage"
42
-
43
- # This is a lie because I will continue to use Archive::Tar::Minitar.
44
- self.need_tar = false
5
+ require 'rake/clean'
6
+
7
+ Hoe.plugin :doofus
8
+ Hoe.plugin :gemspec2
9
+ Hoe.plugin :git
10
+ Hoe.plugin :minitest
11
+ Hoe.plugin :travis
12
+ Hoe.plugin :email unless ENV['CI'] or ENV['TRAVIS']
13
+
14
+ spec = Hoe.spec 'color' do
15
+ developer('Austin Ziegler', 'halostatue@gmail.com')
16
+ developer('Matt Lyon', 'matt@postsomnia.com')
17
+
18
+ license 'MIT'
19
+
20
+ self.history_file = 'History.rdoc'
21
+ self.readme_file = 'README.rdoc'
22
+
23
+ extra_dev_deps << ['hoe-doofus', '~> 1.0']
24
+ extra_dev_deps << ['hoe-gemspec2', '~> 1.1']
25
+ extra_dev_deps << ['hoe-git', '~> 1.6']
26
+ extra_dev_deps << ['hoe-travis', '~> 1.2']
27
+ extra_dev_deps << ['minitest', '~> 5.8']
28
+ extra_dev_deps << ['minitest-around', '~> 0.3']
29
+ extra_dev_deps << ['minitest-autotest', '~> 1.0']
30
+ extra_dev_deps << ['minitest-bisect', '~> 1.2']
31
+ extra_dev_deps << ['minitest-focus', '~> 1.1']
32
+ extra_dev_deps << ['minitest-moar', '~> 0.0']
33
+ extra_dev_deps << ['minitest-pretty_diff', '~> 0.1']
34
+ extra_dev_deps << ['rake', '~> 10.0']
35
+
36
+ if RUBY_VERSION >= '1.9'
37
+ extra_dev_deps << ['simplecov', '~> 0.7']
38
+ extra_dev_deps << ['coveralls', '~> 0.7'] if ENV['CI'] or ENV['TRAVIS']
39
+ end
45
40
  end
46
41
 
47
- desc "Build a Color .tar.gz distribution."
48
- task :tar => [ PKG_TAR ]
49
- file PKG_TAR => [ :test ] do |t|
50
- require 'archive/tar/minitar'
51
- require 'zlib'
52
- files = MANIFEST.map { |f|
53
- fn = File.join(PKG_DIST, f)
54
- tm = File.stat(f).mtime
42
+ if RUBY_VERSION >= '1.9'
43
+ namespace :test do
44
+ if ENV['CI'] or ENV['TRAVIS']
45
+ desc "Submit test coverage to Coveralls"
46
+ task :coveralls do
47
+ spec.test_prelude = [
48
+ 'require "psych"',
49
+ 'require "simplecov"',
50
+ 'require "coveralls"',
51
+ 'SimpleCov.formatter = Coveralls::SimpleCov::Formatter',
52
+ 'SimpleCov.start("test_frameworks") { command_name "Minitest" }',
53
+ 'gem "minitest"'
54
+ ].join('; ')
55
+ Rake::Task['test'].execute
56
+ end
55
57
 
56
- if File.directory?(f)
57
- { :name => fn, :mode => 0755, :dir => true, :mtime => tm }
58
- else
59
- mode = if f =~ %r{^bin}
60
- 0755
61
- else
62
- 0644
63
- end
64
- data = File.read(f)
65
- { :name => fn, :mode => mode, :data => data, :size => data.size,
66
- :mtime => tm }
58
+ Rake::Task['travis'].prerequisites.replace(%w(test:coveralls))
67
59
  end
68
- }
69
60
 
70
- begin
71
- unless File.directory?(File.dirname(t.name))
72
- require 'fileutils'
73
- File.mkdir_p File.dirname(t.name)
61
+ desc "Runs test coverage. Only works Ruby 1.9+ and assumes 'simplecov' is installed."
62
+ task :coverage do
63
+ spec.test_prelude = [
64
+ 'require "simplecov"',
65
+ 'SimpleCov.start("test_frameworks") { command_name "Minitest" }',
66
+ 'gem "minitest"'
67
+ ].join('; ')
68
+ Rake::Task['test'].execute
74
69
  end
75
- tf = File.open(t.name, 'wb')
76
- gz = Zlib::GzipWriter.new(tf)
77
- tw = Archive::Tar::Minitar::Writer.new(gz)
78
70
 
79
- files.each do |entry|
80
- if entry[:dir]
81
- tw.mkdir(entry[:name], entry)
82
- else
83
- tw.add_file_simple(entry[:name], entry) { |os|
84
- os.write(entry[:data])
85
- }
86
- end
87
- end
88
- ensure
89
- tw.close if tw
90
- gz.close if gz
71
+ CLOBBER << 'coverage'
91
72
  end
92
73
  end
93
- task :package => [ PKG_TAR ]
94
-
95
- desc "Build the manifest file from the current set of files."
96
- task :build_manifest do |t|
97
- require 'find'
98
74
 
99
- paths = []
100
- Find.find(".") do |path|
101
- next if File.directory?(path)
102
- next if path =~ /\.svn/
103
- next if path =~ /\.git/
104
- next if path =~ /\.hoerc/
105
- next if path =~ /\.swp$/
106
- next if path =~ %r{coverage/}
107
- next if path =~ /~$/
108
- paths << path.sub(%r{^\./}, '')
109
- end
110
-
111
- File.open("Manifest.txt", "w") do |f|
112
- f.puts paths.sort.join("\n")
113
- end
114
-
115
- puts paths.sort.join("\n")
116
- end
75
+ # vim: syntax=ruby
data/lib/color.rb CHANGED
@@ -1,24 +1,13 @@
1
1
  # :title: Color -- Colour Management with Ruby
2
- # :main: README.txt
3
-
4
- #--
5
- # Color
6
- # Colour management with Ruby
7
- # http://rubyforge.org/projects/color
8
- # Version 1.4.1
9
- #
10
- # Licensed under a MIT-style licence. See Licence.txt in the main
11
- # distribution for full licensing information.
12
- #
13
- # Copyright (c) 2005 - 2010 Austin Ziegler and Matt Lyon
14
- #++
2
+ # :main: README.rdoc
15
3
 
16
4
  # = Colour Management with Ruby
17
5
  module Color
18
- COLOR_VERSION = '1.4.1'
6
+ COLOR_VERSION = '1.8'
19
7
 
20
8
  class RGB; end
21
9
  class CMYK; end
10
+ class HSL; end
22
11
  class GrayScale; end
23
12
  class YIQ; end
24
13
 
@@ -30,65 +19,116 @@ module Color
30
19
  # tolerance value of each other.
31
20
  COLOR_TOLERANCE = 1e-4
32
21
 
33
- class << self
34
- # Returns +true+ if the value is less than COLOR_EPSILON.
35
- def near_zero?(value)
36
- (value.abs <= COLOR_EPSILON)
37
- end
22
+ # Compares the +other+ colour to this one. The +other+ colour will be
23
+ # coerced to the same type as the current colour. Such converted colour
24
+ # comparisons will always be more approximate than non-converted
25
+ # comparisons.
26
+ #
27
+ # If the +other+ colour cannot be coerced to the current colour class, a
28
+ # +NoMethodError+ exception will be raised.
29
+ #
30
+ # All values are compared as floating-point values, so two colours will be
31
+ # reported equivalent if all component values are within COLOR_TOLERANCE
32
+ # of each other.
33
+ def ==(other)
34
+ Color.equivalent?(self, other)
35
+ end
38
36
 
39
- # Returns +true+ if the value is within COLOR_EPSILON of zero or less than
40
- # zero.
41
- def near_zero_or_less?(value)
42
- (value < 0.0 or near_zero?(value))
43
- end
37
+ # The primary name for the colour.
38
+ def name
39
+ names.first
40
+ end
44
41
 
45
- # Returns +true+ if the value is within COLOR_EPSILON of one.
46
- def near_one?(value)
47
- near_zero?(value - 1.0)
48
- end
42
+ # All names for the colour.
43
+ def names
44
+ self.names = nil unless defined? @names
45
+ @names
46
+ end
47
+ def names=(n) # :nodoc:
48
+ @names = Array(n).flatten.compact.map(&:to_s).map(&:downcase).sort.uniq
49
+ end
50
+ alias_method :name=, :names=
51
+ end
49
52
 
50
- # Returns +true+ if the value is within COLOR_EPSILON of one or more than
51
- # one.
52
- def near_one_or_more?(value)
53
- (value > 1.0 or near_one?(value))
54
- end
53
+ class << Color
54
+ # Returns +true+ if the value is less than COLOR_EPSILON.
55
+ def near_zero?(value)
56
+ (value.abs <= Color::COLOR_EPSILON)
57
+ end
55
58
 
56
- # Normalizes the value to the range (0.0) .. (1.0).
57
- def normalize(value)
58
- if near_zero_or_less? value
59
- 0.0
60
- elsif near_one_or_more? value
61
- 1.0
62
- else
63
- value
64
- end
65
- end
66
- alias normalize_fractional normalize
59
+ # Returns +true+ if the value is within COLOR_EPSILON of zero or less than
60
+ # zero.
61
+ def near_zero_or_less?(value)
62
+ (value < 0.0 or near_zero?(value))
63
+ end
67
64
 
68
- def normalize_to_range(value, range)
69
- range = (range.end..range.begin) if (range.end < range.begin)
65
+ # Returns +true+ if the value is within COLOR_EPSILON of one.
66
+ def near_one?(value)
67
+ near_zero?(value - 1.0)
68
+ end
70
69
 
71
- if value <= range.begin
72
- range.begin
73
- elsif value >= range.end
74
- range.end
75
- else
76
- value
77
- end
78
- end
70
+ # Returns +true+ if the value is within COLOR_EPSILON of one or more than
71
+ # one.
72
+ def near_one_or_more?(value)
73
+ (value > 1.0 or near_one?(value))
74
+ end
79
75
 
80
- # Normalize the value to the range (0) .. (255).
81
- def normalize_byte(value)
82
- normalize_to_range(value, 0..255).to_i
76
+ # Returns +true+ if the two values provided are near each other.
77
+ def near?(x, y)
78
+ (x - y).abs <= Color::COLOR_TOLERANCE
79
+ end
80
+
81
+ # Returns +true+ if the two colours are roughly equivalent. If colour
82
+ # conversions are required, this all conversions will be implemented
83
+ # using the default conversion mechanism.
84
+ def equivalent?(a, b)
85
+ return false unless a.kind_of?(Color) && b.kind_of?(Color)
86
+ a.to_a.zip(a.coerce(b).to_a).all? { |(x, y)| near?(x, y) }
87
+ end
88
+
89
+ # Coerces, if possible, the second given colour object to the first
90
+ # given colour object type. This will probably involve colour
91
+ # conversion and therefore a loss of fidelity.
92
+ def coerce(a, b)
93
+ a.coerce(b)
94
+ end
95
+
96
+ # Normalizes the value to the range (0.0) .. (1.0).
97
+ def normalize(value)
98
+ if near_zero_or_less? value
99
+ 0.0
100
+ elsif near_one_or_more? value
101
+ 1.0
102
+ else
103
+ value
83
104
  end
84
- alias normalize_8bit normalize_byte
85
-
86
- # Normalize the value to the range (0) .. (65535).
87
- def normalize_word(value)
88
- normalize_to_range(value, 0..65535).to_i
105
+ end
106
+ alias normalize_fractional normalize
107
+
108
+ # Normalizes the value to the specified range.
109
+ def normalize_to_range(value, range)
110
+ range = (range.end..range.begin) if (range.end < range.begin)
111
+
112
+ if value <= range.begin
113
+ range.begin
114
+ elsif value >= range.end
115
+ range.end
116
+ else
117
+ value
89
118
  end
90
- alias normalize_16bit normalize_word
91
119
  end
120
+
121
+ # Normalize the value to the range (0) .. (255).
122
+ def normalize_byte(value)
123
+ normalize_to_range(value, 0..255).to_i
124
+ end
125
+ alias normalize_8bit normalize_byte
126
+
127
+ # Normalize the value to the range (0) .. (65535).
128
+ def normalize_word(value)
129
+ normalize_to_range(value, 0..65535).to_i
130
+ end
131
+ alias normalize_16bit normalize_word
92
132
  end
93
133
 
94
134
  require 'color/rgb'
@@ -96,10 +136,10 @@ require 'color/cmyk'
96
136
  require 'color/grayscale'
97
137
  require 'color/hsl'
98
138
  require 'color/yiq'
99
- require 'color/rgb/metallic'
139
+ require 'color/css'
100
140
 
101
- module Color
102
- def self.const_missing(name) #:nodoc:
141
+ class << Color
142
+ def const_missing(name) #:nodoc:
103
143
  case name
104
144
  when "VERSION", :VERSION, "COLOR_TOOLS_VERSION", :COLOR_TOOLS_VERSION
105
145
  warn "Color::#{name} has been deprecated. Use Color::COLOR_VERSION instead."
@@ -115,7 +155,7 @@ module Color
115
155
  end
116
156
 
117
157
  # Provides a thin veneer over the Color module to make it seem like this
118
- # is Color 0.1.0 (a class) and not Color 1.4.1 (a module). This
158
+ # is Color 0.1.0 (a class) and not Color 1.4 (a module). This
119
159
  # "constructor" will be removed in the future.
120
160
  #
121
161
  # mode = :hsl:: +values+ must be an array of [ hue deg, sat %, lum % ].
@@ -125,7 +165,7 @@ module Color
125
165
  # Color::RGB object will be created.
126
166
  # mode = :cmyk:: +values+ must be an array of [ cyan %, magenta %, yellow
127
167
  # %, black % ]. A Color::CMYK object will be created.
128
- def self.new(values, mode = :rgb)
168
+ def new(values, mode = :rgb)
129
169
  warn "Color.new has been deprecated. Use Color::#{mode.to_s.upcase}.new instead."
130
170
  color = case mode
131
171
  when :hsl
data/lib/color/cmyk.rb CHANGED
@@ -1,70 +1,44 @@
1
- #--
2
- # Color
3
- # Colour management with Ruby
4
- # http://rubyforge.org/projects/color
5
- # Version 1.4.1
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 - 2010 Austin Ziegler and Matt Lyon
11
- #++
12
-
13
1
  # An CMYK colour object. CMYK (cyan, magenta, yellow, and black) colours are
14
2
  # based on additive percentages of ink. A CMYK colour of (0.3, 0, 0.8, 0.3)
15
3
  # would be mixed from 30% cyan, 0% magenta, 80% yellow, and 30% black.
16
4
  # Primarily used in four-colour printing processes.
17
5
  class Color::CMYK
6
+ include Color
7
+
18
8
  # The format of a DeviceCMYK colour for PDF. In color-tools 2.0 this will
19
9
  # be removed from this package and added back as a modification by the
20
10
  # PDF::Writer package.
21
11
  PDF_FORMAT_STR = "%.3f %.3f %.3f %.3f %s"
22
12
 
23
- # Compares the other colour to this one. The other colour will be
24
- # converted to CMYK before comparison, so the comparison between a CMYK
25
- # colour and a non-CMYK colour will be approximate and based on the other
26
- # colour's #to_cmyk conversion. If there is no #to_cmyk conversion, this
27
- # will raise an exception. This will report that two CMYK colours are
28
- # equivalent if all component values are within COLOR_TOLERANCE of each
29
- # other.
30
- def ==(other)
31
- other = other.to_cmyk
32
- other.kind_of?(Color::CMYK) and
33
- ((@c - other.c).abs <= Color::COLOR_TOLERANCE) and
34
- ((@m - other.m).abs <= Color::COLOR_TOLERANCE) and
35
- ((@y - other.y).abs <= Color::COLOR_TOLERANCE) and
36
- ((@k - other.k).abs <= Color::COLOR_TOLERANCE)
13
+ # Coerces the other Color object into CMYK.
14
+ def coerce(other)
15
+ other.to_cmyk
37
16
  end
38
17
 
39
- # Creates a CMYK colour object from fractional values 0..1.
40
- #
41
- # Color::CMYK.from_fraction(0.3, 0, 0.8, 0.3)
42
- def self.from_fraction(c = 0, m = 0, y = 0, k = 0)
43
- colour = Color::CMYK.new
44
- colour.c = c
45
- colour.m = m
46
- colour.y = y
47
- colour.k = k
48
- colour
49
- end
18
+ class << self
19
+ # Creates a CMYK colour object from fractional values 0..1.
20
+ #
21
+ # Color::CMYK.from_fraction(0.3, 0, 0.8, 0.3)
22
+ def from_fraction(c = 0, m = 0, y = 0, k = 0, &block)
23
+ new(c, m, y, k, 1.0, &block)
24
+ end
50
25
 
51
- # Creates a CMYK colour object from percentages. Internally, the colour is
52
- # managed as fractional values 0..1.
53
- #
54
- # Color::CMYK.new(30, 0, 80, 30)
55
- def self.from_percent(c = 0, m = 0, y = 0, k = 0)
56
- Color::CMYK.new(c, m, y, k)
26
+ # Creates a CMYK colour object from percentages. Internally, the colour is
27
+ # managed as fractional values 0..1.
28
+ #
29
+ # Color::CMYK.new(30, 0, 80, 30)
30
+ def from_percent(c = 0, m = 0, y = 0, k = 0, &block)
31
+ new(c, m, y, k, &block)
32
+ end
57
33
  end
58
34
 
59
35
  # Creates a CMYK colour object from percentages. Internally, the colour is
60
36
  # managed as fractional values 0..1.
61
37
  #
62
38
  # Color::CMYK.new(30, 0, 80, 30)
63
- def initialize(c = 0, m = 0, y = 0, k = 0)
64
- @c = c / 100.0
65
- @m = m / 100.0
66
- @y = y / 100.0
67
- @k = k / 100.0
39
+ def initialize(c = 0, m = 0, y = 0, k = 0, radix = 100.0, &block) # :yields self:
40
+ @c, @m, @y, @k = [ c, m, y, k ].map { |v| Color.normalize(v / radix) }
41
+ block.call(self) if block
68
42
  end
69
43
 
70
44
  # Present the colour as a DeviceCMYK fill colour string for PDF. This will
@@ -96,8 +70,8 @@ class Color::CMYK
96
70
  # Present the colour as an RGBA (with alpha) HTML/CSS colour string (e.g.,
97
71
  # "rgb(0%, 50%, 100%, 1)"). Note that this will perform a #to_rgb
98
72
  # operation using the default conversion formula.
99
- def css_rgba
100
- to_rgb.css_rgba
73
+ def css_rgba(alpha = 1)
74
+ to_rgb.css_rgba(alpha)
101
75
  end
102
76
 
103
77
  # Present the colour as an HSL HTML/CSS colour string (e.g., "hsl(180,
@@ -150,15 +124,10 @@ class Color::CMYK
150
124
  # profiles.
151
125
  def to_rgb(use_adobe_method = false)
152
126
  if use_adobe_method
153
- r = 1.0 - [1.0, @c + @k].min
154
- g = 1.0 - [1.0, @m + @k].min
155
- b = 1.0 - [1.0, @y + @k].min
127
+ Color::RGB.from_fraction(*adobe_cmyk_rgb)
156
128
  else
157
- r = 1.0 - (@c.to_f * (1.0 - @k.to_f) + @k.to_f)
158
- g = 1.0 - (@m.to_f * (1.0 - @k.to_f) + @k.to_f)
159
- b = 1.0 - (@y.to_f * (1.0 - @k.to_f) + @k.to_f)
129
+ Color::RGB.from_fraction(*standard_cmyk_rgb)
160
130
  end
161
- Color::RGB.from_fraction(r, g, b)
162
131
  end
163
132
 
164
133
  # Converts the CMYK colour to a single greyscale value. There are
@@ -276,4 +245,19 @@ class Color::CMYK
276
245
  def k=(kk)
277
246
  @k = Color.normalize(kk)
278
247
  end
248
+
249
+ def to_a
250
+ [ c, m, y, k ]
251
+ end
252
+
253
+ private
254
+ # Implements the Adobe PDF conversion of CMYK to RGB.
255
+ def adobe_cmyk_rgb
256
+ [ @c, @m, @y ].map { |v| 1.0 - [ 1.0, v + @k ].min }
257
+ end
258
+
259
+ # Implements the standard conversion of CMYK to RGB.
260
+ def standard_cmyk_rgb
261
+ [ @c, @m, @y ].map { |v| 1.0 - (v * (1.0 - k) + k) }
262
+ end
279
263
  end