red-colors 0.2.0 → 0.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.
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