red-colors 0.2.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/data/colormaps/cividis.json +258 -0
  3. data/data/colormaps/coolwarm.json +107 -0
  4. data/data/colormaps/crest.json +258 -0
  5. data/data/colormaps/flare.json +258 -0
  6. data/data/colormaps/gist_earth.json +49 -0
  7. data/data/colormaps/gist_ncar.json +55 -0
  8. data/data/colormaps/icefire.json +258 -0
  9. data/data/colormaps/inferno.json +258 -0
  10. data/data/colormaps/magma.json +258 -0
  11. data/data/colormaps/mako.json +258 -0
  12. data/data/colormaps/nipy_spectral.json +71 -0
  13. data/data/colormaps/pink.json +200 -0
  14. data/data/colormaps/plasma.json +258 -0
  15. data/data/colormaps/rocket.json +258 -0
  16. data/data/colormaps/turbo.json +258 -0
  17. data/data/colormaps/twilight.json +512 -0
  18. data/data/colormaps/viridis.json +258 -0
  19. data/data/colormaps/vlag.json +258 -0
  20. data/doc/text/news.md +23 -0
  21. data/lib/colors/colormap.rb +12 -0
  22. data/lib/colors/colormap_data/matplotlib_builtin.rb +990 -0
  23. data/lib/colors/colormap_data/seaborn_builtin.rb +10 -0
  24. data/lib/colors/colormap_data.rb +44 -0
  25. data/lib/colors/colormap_registry.rb +61 -0
  26. data/lib/colors/convert.rb +6 -0
  27. data/lib/colors/css.rb +63 -0
  28. data/lib/colors/helper.rb +2 -1
  29. data/lib/colors/linear_segmented_colormap.rb +19 -3
  30. data/lib/colors/listed_colormap.rb +4 -0
  31. data/lib/colors/version.rb +1 -1
  32. data/lib/colors/xterm256.rb +2 -1
  33. data/lib/colors.rb +4 -0
  34. data/red-colors.gemspec +2 -0
  35. data/test/run.rb +1 -2
  36. data/test/test-css.rb +174 -0
  37. data/test/test-linear-segmented-colormap.rb +19 -0
  38. data/test/test-listed-colormap.rb +19 -0
  39. data/test/test-xterm256.rb +18 -4
  40. metadata +46 -6
@@ -0,0 +1,10 @@
1
+ module Colors
2
+ module ColormapRegistry
3
+ register_listed_colormap("rocket")
4
+ register_listed_colormap("mako")
5
+ register_listed_colormap("icefire")
6
+ register_listed_colormap("vlag")
7
+ register_listed_colormap("flare")
8
+ register_listed_colormap("crest")
9
+ end
10
+ end
@@ -0,0 +1,44 @@
1
+ require "json"
2
+ require "pathname"
3
+
4
+ module Colors
5
+ module ColormapRegistry
6
+ BUILTIN_COLORMAPS = {}
7
+ LUT_SIZE = 512
8
+
9
+ top_dir = Pathname.new(__dir__).parent.parent
10
+ @colormaps_dir = top_dir.join("data", "colormaps")
11
+
12
+ def self.load_colormap_data(name)
13
+ path = @colormaps_dir.join("#{name}.json")
14
+ json = File.read(path)
15
+ JSON.load(json, nil, symbolize_names: true, create_additions: false)
16
+ end
17
+
18
+ def self.register_listed_colormap(name, data=nil)
19
+ data = load_colormap_data(name) if data.nil?
20
+ colors = data.map {|r, g, b| Colors::RGB.new(r, g, b) }
21
+ BUILTIN_COLORMAPS[name] = ListedColormap.new(colors, name: name)
22
+ end
23
+
24
+ require_relative "colormap_data/matplotlib_builtin.rb"
25
+ require_relative "colormap_data/seaborn_builtin.rb"
26
+
27
+ class << self
28
+ undef load_colormap_data
29
+ undef register_listed_colormap
30
+ end
31
+
32
+ # Generate reversed colormaps
33
+ cmaps_r = BUILTIN_COLORMAPS.each_value.map(&:reversed)
34
+ cmaps_r.each do |cmap_r|
35
+ BUILTIN_COLORMAPS[cmap_r.name] = cmap_r
36
+ end
37
+
38
+ BUILTIN_COLORMAPS.freeze
39
+
40
+ BUILTIN_COLORMAPS.each do |name, cmap|
41
+ @registry[name] = cmap
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,61 @@
1
+ module Colors
2
+ module ColormapRegistry
3
+ @registry = {}
4
+
5
+ def self.[](name)
6
+ return name if name.is_a?(Colormap)
7
+
8
+ name = String.try_convert(name)
9
+ if @registry.key?(name)
10
+ return @registry[name]
11
+ else
12
+ raise ArgumentError, "Unknown colormap name: %p" % name
13
+ end
14
+ end
15
+
16
+ def self.register(cmap, name: nil, override_builtin: false)
17
+ case name
18
+ when String, Symbol
19
+ name = name.to_s
20
+ when nil
21
+ name = cmap.name
22
+ if name.nil?
23
+ raise ArgumentError, "`name` cannot be omitted for unnamed colormaps"
24
+ end
25
+ else
26
+ name = String.try_convert(name)
27
+ if name.nil?
28
+ raise ArgumentError, "`name` must be convertible to a String by to_str"
29
+ end
30
+ end
31
+
32
+ if @registry.key?(name)
33
+ if BUILTIN_COLORMAPS.key?(name)
34
+ unless override_builtin
35
+ raise ArgumentError,
36
+ "Trying to re-register a builtin colormap: %p" % name
37
+ end
38
+ end
39
+ warn "Trying to re-register the colormap %p which already exists" % name
40
+ end
41
+
42
+ unless cmap.is_a?(Colormap)
43
+ raise ArgumentError,
44
+ "Invalid value for registering a colormap (%p for a Colormap)" % cmap
45
+ end
46
+
47
+ @registry[name] = cmap
48
+ end
49
+
50
+ def self.unregister(name)
51
+ if @registry.key?(name)
52
+ if BUILTIN_COLORMAPS.key?(name)
53
+ raise ArgumentError,
54
+ "Unable to unregister the colormap %p which is a builtin colormap" % name
55
+ end
56
+ else
57
+ @registry.delete(name)
58
+ end
59
+ end
60
+ end
61
+ end
@@ -150,6 +150,12 @@ module Colors
150
150
  dot_product(RGB2XYZ, srgb_to_linear_srgb(r, g, b))
151
151
  end
152
152
 
153
+ def rgb_to_greyscale(r, g, b)
154
+ r, g, b = srgb_to_linear_srgb(r, g, b)
155
+ a = RGB2XYZ[1]
156
+ (a[0]*r + a[1]*g + a[2]*b).clamp(0, 1)
157
+ end
158
+
153
159
  def rgb_to_xterm256(r, g, b)
154
160
  i = closest_xterm256_rgb_index(r)
155
161
  j = closest_xterm256_rgb_index(g)
data/lib/colors/css.rb ADDED
@@ -0,0 +1,63 @@
1
+ module Colors
2
+ module CSS
3
+ # Factory method for generating RGB/RGBA/HSL/HSLA Objects.
4
+ # Parsing based on spec https://www.w3.org/TR/css-color-3 ; section 4.2
5
+ def self.parse(css_string)
6
+ error_message = "must be a string of `rgb(rr,gg,bb)`, `rgba(rr,gg,bb,aa)`, `hsl(hh,ss,ll)`, or `hsla(hh,ss,ll,aa)` form"
7
+ unless css_string.respond_to?(:to_str)
8
+ raise ArgumentError, "#{error_message}: #{css_string.inspect}"
9
+ end
10
+
11
+ css_string = css_string.to_str.strip
12
+
13
+ matcher = /\A((?:rgb|hsl)a?)\(([^)]+)\)\z/.match(css_string)
14
+ unless matcher
15
+ raise ArgumentError, "#{error_message}: #{css_string.inspect}"
16
+ end
17
+
18
+ color_space, args_string = matcher[1..2]
19
+ args = args_string.strip.split(/\s*,\s*/)
20
+ has_alpha = color_space.end_with?("a") # rgba/hsla
21
+ if has_alpha && args.length != 4
22
+ raise ArgumentError, "Expecting 4 fields for #{color_space}(): #{css_string.inspect}"
23
+ elsif !has_alpha && args.length != 3
24
+ raise ArgumentError, "Expecting 3 fields for #{color_space}(): #{css_string.inspect}"
25
+ end
26
+
27
+ case color_space
28
+ when "rgb", "rgba"
29
+ rgb, alpha = args[0, 3], args[3]
30
+ num_percent_vals = rgb.count {|v| v.end_with?("%") }
31
+ # CSS3 allows RGB values to be specified with all 3 as a percentage "##%"
32
+ # or all as integer values without '%' sign.
33
+ if num_percent_vals.zero?
34
+ # interpret as integer values in range of 0..255
35
+ r, g, b = rgb.map {|strval| strval.to_i.clamp(0, 255) }
36
+ # Note, RGBA.new expects all values to be integers or floats.
37
+ # For this case, we also turn the alpha-value into an int range 0..255
38
+ # to match the r,g,b values.
39
+ a = has_alpha && (alpha.to_r.clamp(0r, 1r) * 255).to_i
40
+ elsif num_percent_vals == 3
41
+ r, g, b = rgb.map {|strval| (strval.to_r / 100).clamp(0r, 1r) }
42
+ a = has_alpha && alpha.to_r.clamp(0r, 1r)
43
+ else
44
+ raise ArgumentError, "Invalid mix of percent and integer values: #{css_string.inspect}"
45
+ end
46
+ return has_alpha ? RGBA.new(r, g, b, a) : RGB.new(r, g, b)
47
+ when "hsl", "hsla"
48
+ hue, sat, light, alpha = *args
49
+ # CSS3 Hue values are an angle, unclear if we should convert to Integer or Rational here.
50
+ h = hue.to_r
51
+ s, l = [sat, light].map {|strval| (strval.to_r / 100).clamp(0r, 1r) }
52
+ if has_alpha
53
+ a = alpha.to_r.clamp(0r, 1r)
54
+ return HSLA.new(h, s, l, a)
55
+ else
56
+ return HSL.new(h, s, l)
57
+ end
58
+ else
59
+ raise ArgumentError, "Unknown color space: #{css_string.inspect}"
60
+ end
61
+ end
62
+ end
63
+ end
data/lib/colors/helper.rb CHANGED
@@ -7,7 +7,8 @@ module Colors
7
7
 
8
8
  private def check_range(value, range, name)
9
9
  return value if range.cover?(value)
10
- check_fail ArgumentError, "#{name} must be in #{range}, but #{value} is given"
10
+ check_fail ArgumentError,
11
+ "#{name} must be in #{range}, but %p is given" % value
11
12
  end
12
13
 
13
14
  private def check_fail(exc_class, message)
@@ -17,7 +17,7 @@ module Colors
17
17
  else
18
18
  ary = Array.try_convert(colors)
19
19
  if ary.nil?
20
- raise ArgumentError, "colors must be convertible to an array"
20
+ raise ArgumentError, "colors must be convertible to an array: %p for %s" % [colors, name]
21
21
  else
22
22
  colors = ary
23
23
  end
@@ -80,8 +80,6 @@ module Colors
80
80
  raise ArgumentError, "data array must consist of 3-length arrays"
81
81
  end
82
82
 
83
- shape = [ary.length, 3]
84
-
85
83
  x, y0, y1 = ary.transpose
86
84
 
87
85
  if x[0] != 0.0 || x[-1] != 1.0
@@ -115,5 +113,23 @@ module Colors
115
113
 
116
114
  return lut.map {|v| v.clamp(0, 1).to_f }
117
115
  end
116
+
117
+ private def make_reverse_colormap(name)
118
+ segmented_data_r = self.segmented_data.map { |key, data|
119
+ data_r = if data.respond_to?(:call)
120
+ make_inverse_func(data)
121
+ else
122
+ data.reverse_each.map do |x, y0, y1|
123
+ [1r - x, y1, y0]
124
+ end
125
+ end
126
+ [key, data_r]
127
+ }.to_h
128
+ LinearSegmentedColormap.new(name, segmented_data_r, n_colors: self.n_colors, gamma: self.gamma)
129
+ end
130
+
131
+ private def make_inverse_func(f)
132
+ ->(x) { f(1 - x) }
133
+ end
118
134
  end
119
135
  end
@@ -37,5 +37,9 @@ module Colors
37
37
  @initialized = true
38
38
  update_extreme_colors
39
39
  end
40
+
41
+ private def make_reverse_colormap(name)
42
+ ListedColormap.new(self.colors.reverse, name: name, n_colors: self.n_colors)
43
+ end
40
44
  end
41
45
  end
@@ -1,3 +1,3 @@
1
1
  module Colors
2
- VERSION = "0.2.0"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -42,7 +42,8 @@ module Colors
42
42
  def to_grey_level
43
43
  if code < 232
44
44
  r, g, b = to_rgb_components
45
- x, y, z = Convet.rgb_to_xyz(r, g, b)
45
+ y = Convert.rgb_to_greyscale(r, g, b)
46
+ canonicalize_component_to_rational(y, :grey)
46
47
  else
47
48
  grey = 10*(code - 232) + 8
48
49
  canonicalize_component_from_integer(grey, :grey)
data/lib/colors.rb CHANGED
@@ -4,6 +4,7 @@ require_relative "colors/convert"
4
4
  require_relative "colors/helper"
5
5
 
6
6
  require_relative "colors/abstract_color"
7
+ require_relative "colors/css"
7
8
  require_relative "colors/hsl"
8
9
  require_relative "colors/hsla"
9
10
  require_relative "colors/husl"
@@ -19,6 +20,7 @@ require_relative "colors/named_colors"
19
20
  require_relative "colors/colormap"
20
21
  require_relative "colors/listed_colormap"
21
22
  require_relative "colors/linear_segmented_colormap"
23
+ require_relative "colors/colormap_registry"
22
24
 
23
25
  module Colors
24
26
  # ITU-R BT.709 D65 white point
@@ -37,3 +39,5 @@ module Colors
37
39
  NamedColors[name]
38
40
  end
39
41
  end
42
+
43
+ require_relative "colors/colormap_data"
data/red-colors.gemspec CHANGED
@@ -27,11 +27,13 @@ Gem::Specification.new do |spec|
27
27
  "#{spec.name}.gemspec",
28
28
  ]
29
29
  spec.files += [".yardopts"]
30
+ spec.files += Dir.glob("data/colormaps/*.json")
30
31
  spec.files += Dir.glob("lib/**/*.rb")
31
32
  spec.files += Dir.glob("image/*.*")
32
33
  spec.files += Dir.glob("doc/text/*")
33
34
  spec.test_files += Dir.glob("test/**/*")
34
35
 
36
+ spec.add_runtime_dependency("json")
35
37
  spec.add_runtime_dependency("matrix")
36
38
 
37
39
  spec.add_development_dependency("bundler")
data/test/run.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- # TODO
4
- # $VERBOSE = true
3
+ $VERBOSE = true
5
4
 
6
5
  require "pathname"
7
6
 
data/test/test-css.rb ADDED
@@ -0,0 +1,174 @@
1
+ class ColorsCSSParserTest < Test::Unit::TestCase
2
+ include TestHelper
3
+
4
+ sub_test_case("rgb") do
5
+ test("simple in-range integer values") do
6
+ ref = Colors::RGB.new(1, 0, 255)
7
+ css = Colors::CSS.parse("rgb(1,0,255)")
8
+ assert_near(ref, css)
9
+ end
10
+
11
+ test("clamps out-of-range integer values") do
12
+ ref = Colors::RGB.new(255, 0, 0)
13
+ css = Colors::CSS.parse("rgb( 300 ,0,0)")
14
+ assert_near(ref, css)
15
+ css = Colors::CSS.parse("rgb( 255 , -10,0)")
16
+ assert_near(ref, css)
17
+ end
18
+
19
+ test("in-range percent values") do
20
+ ref = Colors::RGB.new(0, 0.55, 1)
21
+ css = Colors::CSS.parse("rgb(0%,55%,100%)")
22
+ assert_near(ref, css)
23
+ end
24
+
25
+ test("clamps out-of-range percent values") do
26
+ ref = Colors::RGB.new(0r, 0r, 1r)
27
+ css = Colors::CSS.parse("rgb(0%,0%,110%)")
28
+ assert_near(ref, css)
29
+ css = Colors::CSS.parse("rgb(-10%,0%,100%)")
30
+ assert_near(ref, css)
31
+ end
32
+
33
+ test("bad input") do
34
+ assert_raises ArgumentError, "mixed pct/int" do
35
+ Colors::CSS.parse("rgb(50%,0 ,0)")
36
+ end
37
+ assert_raises ArgumentError, "too few args" do
38
+ Colors::CSS.parse("rgb(50%,0%)")
39
+ end
40
+ assert_raises ArgumentError, "too many args" do
41
+ Colors::CSS.parse("rgb(50%,0%,6%,0)")
42
+ end
43
+ assert_raises ArgumentError, "missing comma" do
44
+ Colors::CSS.parse("rgb(50% 0% 6%)")
45
+ end
46
+ end
47
+ end
48
+
49
+ sub_test_case("rgba") do
50
+ test("integer values, int alpha") do
51
+ ref = Colors::RGBA.new(1r, 0r, 1r, 1r)
52
+ css = Colors::CSS.parse("rgba(255,0,255,1)")
53
+ assert_near(ref, css)
54
+ ref = Colors::RGBA.new(1r, 0r, 1r, 0r)
55
+ css = Colors::CSS.parse("rgba(255,0,255,0)")
56
+ assert_near(ref, css)
57
+ end
58
+
59
+ test("integer values, float alpha") do
60
+ ref = Colors::RGBA.new(255, 0, 255, 127)
61
+ css = Colors::CSS.parse("rgba(255,0,255 , 0.5)")
62
+ assert_near(ref, css)
63
+ end
64
+
65
+ test("clamp out of range alpha values") do
66
+ ref = Colors::RGBA.new(1r, 0, 1r, 1r)
67
+ css = Colors::CSS.parse("rgba(255,0,255,2.0)")
68
+ assert_near(ref, css)
69
+ ref = Colors::RGBA.new(1r, 127/255r, 123/255r, 0.0)
70
+ css = Colors::CSS.parse("rgba(255, 127, 123,-0.1)")
71
+ assert_near(ref, css)
72
+ end
73
+
74
+ test("percent values, int alpha") do
75
+ ref = Colors::RGBA.new(1r, 0r, 0.25r, 1r)
76
+ css = Colors::CSS.parse("rgba(100%,0%,25%,1)")
77
+ assert_near(ref, css)
78
+ ref = Colors::RGBA.new(1r, 0.33r, 0.02r, 0r)
79
+ css = Colors::CSS.parse("rgba(100% , 33%,2%,0)")
80
+ assert_near(ref, css)
81
+ end
82
+
83
+ test("percent values, float alpha") do
84
+ ref = Colors::RGBA.new(0.5r, 0, 0.06, 1/2r)
85
+ css = Colors::CSS.parse("rgba(50%,0%,6% ,0.5)")
86
+ assert_near(ref, css)
87
+ end
88
+
89
+ test("bad input") do
90
+ assert_raises ArgumentError, "mixed pct/int" do
91
+ Colors::CSS.parse("rgba(50%,0,6 ,0.5)")
92
+ end
93
+ assert_raises ArgumentError, "too few args" do
94
+ Colors::CSS.parse("rgba(50%,0%,6%)")
95
+ end
96
+ assert_raises ArgumentError, "too many args" do
97
+ Colors::CSS.parse("rgba(50%,0%,6%,0.5, 0.5)")
98
+ end
99
+ assert_raises ArgumentError, "missing comma" do
100
+ Colors::CSS.parse("rgba(50%,0%,6% 0.5)")
101
+ end
102
+ end
103
+ end
104
+
105
+ sub_test_case("hsl") do
106
+ test("in-range hsl") do
107
+ ref = Colors::HSL.new(180, 0, 0.5)
108
+ css = Colors::CSS.parse("hsl( 180, 0% , 50% )")
109
+ assert_near(ref, css)
110
+ end
111
+
112
+ test("clamps out-of-range integer values") do
113
+ ref = Colors::HSL.new(180, 0, 0.5)
114
+ css = Colors::CSS.parse("hsl(-180,0%,50%)")
115
+ assert_near(ref, css)
116
+ css = Colors::CSS.parse("hsl(180,-10%,50%)")
117
+ assert_near(ref, css)
118
+ css = Colors::CSS.parse("hsl(540,-10%,50%)")
119
+ assert_near(ref, css)
120
+ ref = Colors::HSL.new(0, 1.0, 1.0)
121
+ css = Colors::CSS.parse("hsl(0,100%,100%)")
122
+ assert_near(ref, css)
123
+ css = Colors::CSS.parse("hsl(360,100%,100%)")
124
+ assert_near(ref, css)
125
+ end
126
+
127
+ test("bad input") do
128
+ assert_raises ArgumentError, "too many args" do
129
+ css = Colors::CSS.parse("hsl( 180, 0% , 50%, 50% )")
130
+ end
131
+ assert_raises ArgumentError, "too few args" do
132
+ css = Colors::CSS.parse("hsl( 180, 0%)")
133
+ end
134
+ assert_raises ArgumentError, "missing comma" do
135
+ css = Colors::CSS.parse("hsl( 180, 0% 50% )")
136
+ end
137
+ end
138
+ end
139
+
140
+ sub_test_case("hsla") do
141
+ test("in-range hsla") do
142
+ ref = Colors::HSLA.new(180, 0, 0.5, 1.0)
143
+ css = Colors::CSS.parse("hsla( 180, 0% , 50%,1.0)")
144
+ assert_near(ref, css)
145
+ end
146
+
147
+ test("clamps out-of-range integer values") do
148
+ ref = Colors::HSLA.new(180, 0, 0.5, 0.1)
149
+ css = Colors::CSS.parse("hsla(-180,0%,50%,0.1)")
150
+ assert_near(ref, css)
151
+ css = Colors::CSS.parse("hsla(180,-10%,50%, 0.1)")
152
+ assert_near(ref, css)
153
+ css = Colors::CSS.parse("hsla(540,-10%,50%, 0.1)")
154
+ assert_near(ref, css)
155
+ ref = Colors::HSLA.new(0, 1.0, 1.0, 0.0)
156
+ css = Colors::CSS.parse("hsla(0,100%,100%,0.0)")
157
+ assert_near(ref, css)
158
+ css = Colors::CSS.parse("hsla(360,100%,100%, 0.0)")
159
+ assert_near(ref, css)
160
+ end
161
+
162
+ test("bad input") do
163
+ assert_raises ArgumentError, "too many args" do
164
+ css = Colors::CSS.parse("hsla( 180, 0% , 50%, 0.0, 0.0 )")
165
+ end
166
+ assert_raises ArgumentError, "too few args" do
167
+ css = Colors::CSS.parse("hsla( 180, 0%, 0.0)")
168
+ end
169
+ assert_raises ArgumentError, "missing comma" do
170
+ css = Colors::CSS.parse("hsla( 180, 0% 50% 0.0 )")
171
+ end
172
+ end
173
+ end
174
+ end
@@ -115,5 +115,24 @@ class ColorsLinearSegmentedColormapTest < Test::Unit::TestCase
115
115
  after
116
116
  ])
117
117
  end
118
+
119
+ def test_reversed
120
+ cm = Colors::LinearSegmentedColormap.new_from_list("four", [:red, :magenta, :green, :yellow, :blue], n_colors: 5)
121
+ cm.under_color = :black
122
+ cm.over_color = :white
123
+ rev = cm.reversed
124
+ assert_equal([
125
+ "four_r",
126
+ cm[[0, 1, 2, 3, 4]],
127
+ Colors[:black],
128
+ Colors[:white]
129
+ ],
130
+ [
131
+ rev.name,
132
+ rev[[4, 3, 2, 1, 0]],
133
+ rev.under_color,
134
+ rev.over_color
135
+ ])
136
+ end
118
137
  end
119
138
 
@@ -112,4 +112,23 @@ class ColorsListedColormapTest < Test::Unit::TestCase
112
112
  after
113
113
  ])
114
114
  end
115
+
116
+ def test_reversed
117
+ cm = Colors::ListedColormap.new([:red, :green, :blue], name: "three")
118
+ cm.under_color = :orange
119
+ cm.over_color = :yellow
120
+ rev = cm.reversed
121
+ assert_equal([
122
+ "three_r",
123
+ cm[[0, 1, 2]],
124
+ Colors[:orange],
125
+ Colors[:yellow]
126
+ ],
127
+ [
128
+ rev.name,
129
+ rev[[2, 1, 0]],
130
+ rev.under_color,
131
+ rev.over_color
132
+ ])
133
+ end
115
134
  end
@@ -44,7 +44,9 @@ class ColorsXterm256Test < Test::Unit::TestCase
44
44
  assert { Colors::Xterm256.new(16) != Colors::Xterm256.new(17) }
45
45
  end
46
46
 
47
- data do
47
+ RGB2GREY = [0.21263900587151035754r, 0.71516867876775592746r, 0.07219231536073371500r]
48
+
49
+ data(keep: true) do
48
50
  data_set = {}
49
51
  # colors 16-231 are a 6x6x6 color cube
50
52
  (0...6).each do |r|
@@ -55,7 +57,10 @@ class ColorsXterm256Test < Test::Unit::TestCase
55
57
  green = (g > 0) ? 40*g + 55 : g
56
58
  blue = (b > 0) ? 40*b + 55 : b
57
59
  label = "Color #{code} is rgb(#{red}, #{green}, #{blue})"
58
- data_set[label] = [code, Colors::RGB.new(red, green, blue)]
60
+ rgb = Colors::RGB.new(red, green, blue)
61
+ red, green, blue = Colors::Convert.srgb_to_linear_srgb(*rgb.components)
62
+ grey = RGB2GREY[0]*red + RGB2GREY[1]*green + RGB2GREY[2]*blue
63
+ data_set[label] = [code, rgb, grey]
59
64
  end
60
65
  end
61
66
  end
@@ -63,14 +68,23 @@ class ColorsXterm256Test < Test::Unit::TestCase
63
68
  (0...24).each do |y|
64
69
  code = 232 + y
65
70
  level = 10*y + 8
71
+ grey = level/255r
66
72
  label = "Color #{code} is gray(#{level})"
67
- data_set[label] = [code, Colors::RGB.new(level, level, level)]
73
+ data_set[label] = [code, Colors::RGB.new(level, level, level), grey]
68
74
  end
69
75
  data_set
70
76
  end
77
+
71
78
  def test_to_rgb(data)
72
- code, rgb = data
79
+ code, rgb, _grey = data
73
80
  assert_equal(rgb,
74
81
  Colors::Xterm256.new(code).to_rgb)
75
82
  end
83
+
84
+ def test_to_grey_level(data)
85
+ code, _rgb, grey = data
86
+ assert_in_delta(grey,
87
+ Colors::Xterm256.new(code).to_grey_level,
88
+ 1e-12)
89
+ end
76
90
  end