redgreenblue 0.9.0 → 0.14.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.
@@ -0,0 +1,13 @@
1
+ class RGB
2
+
3
+ # Returns the name.
4
+ def name
5
+ defined?(@name) ? @name : nil
6
+ end
7
+
8
+ # Sets the name (a string or nil).
9
+ def name=(text)
10
+ @name = ( text.to_s.size != 0 ) ? text.to_s : nil
11
+ end
12
+
13
+ end
@@ -1,18 +1,28 @@
1
1
  # Optional support for Philips Hue lights.
2
2
  #
3
3
  # Conforms to Bridge API 1.35 for Philips Hue, published 20-Nov-2019.
4
- # See (regrettably requires registration):
5
- # - https://developers.meethue.com/develop/hue-api/
6
4
 
7
5
  # Automatically load core RGB class before loading options.
8
6
  require 'redgreenblue'
9
7
 
10
8
  class RGB
11
9
 
12
- # Returns the arguments required by the Philips Hue API to set a light to this RGB object's hue, saturation and brightness (HSB).
10
+ # Only available when optional support for Philips Hue lights is loaded.
13
11
  #
14
- # When formatted as JSON, this hash can be used directly to set a light's state.
15
- # Only available when optional support for Philips Hue lights is loaded (require 'redgreenblue/opt/philipshue').
12
+ # Returns a hash with the arguments required by the Philips Hue API,
13
+ # to set a light to this RGB object's hue, saturation and brightness.
14
+ #
15
+ # Formatted as JSON, this hash can be sent to a bridge to set a light's state.
16
+ #
17
+ # See (regrettably requires registration):
18
+ # - https://developers.meethue.com/develop/hue-api/
19
+ #
20
+ # @example Load
21
+ # require 'redgreenblue/opt/philipshue'
22
+ # @example Use
23
+ # RGB.magenta.to_philips_hue_api_hsb_arguments
24
+ # => {"on"=>true, "bri"=>254, "hue"=>54613, "sat"=>254}
25
+ # @return [Hash] API arguments
16
26
  def to_philips_hue_api_hsb_arguments(black_off=true)
17
27
  my_hsb = hsb
18
28
 
@@ -3,7 +3,7 @@ class RGB
3
3
  # On Mac OS, shows the color picker to choose a color for the RGB object.
4
4
  # Not available on other platforms.
5
5
  def pick
6
- result = RGB.mac_choose(rrggbb)
6
+ result = RGB.mac_choose(self)
7
7
  if result
8
8
  self.rrggbb = result
9
9
  end
@@ -14,7 +14,7 @@ class RGB
14
14
  #
15
15
  # If no default color is specified, the picker defaults to a middle grey.
16
16
  def self.pick(default_color=RGB.new)
17
- result = RGB.mac_choose(default_color.rrggbb)
17
+ result = RGB.mac_choose(default_color)
18
18
  if result
19
19
  RGB.rrggbb result
20
20
  else
@@ -32,7 +32,7 @@ class RGB
32
32
  #
33
33
  # Applescript command documented here:
34
34
  # Standard Additions -> User Interaction -> choose color
35
- def self.mac_choose(color)
35
+ def self.mac_choose(default_color)
36
36
 
37
37
  app = case ENV['TERM_PROGRAM']
38
38
  when /iTerm\.app/
@@ -44,7 +44,7 @@ class RGB
44
44
  script = <<~ENDSCRIPT
45
45
  tell application "#{app}"
46
46
  try
47
- return choose color default color { #{color[0]}, #{color[1]}, #{color[2]} }
47
+ return choose color default color #{default_color.applescript}
48
48
  on error
49
49
  return ""
50
50
  end try
@@ -0,0 +1,45 @@
1
+ class RGB
2
+
3
+ # Returns a new RGB object with this color's Ostwald full-color,
4
+ # or nil for achromatic colors (white, greys, and black).
5
+ #
6
+ # The resulting color contains no white or black,
7
+ # i.e. it has at least one RGB component set to 0, and at least one set to maximum.
8
+ #
9
+ # This is identical (barring very small rounding errors)
10
+ # to setting HSL-saturation to 1, and -lightness to 0.5
11
+ #
12
+ # Based on:
13
+ # - Color for the Sciences, pp. 575–591
14
+ # - https://lirias.kuleuven.be/retrieve/306124 (PDF)
15
+ def ostwald_color
16
+ white_portion = values.min
17
+ color_portion = values.max - white_portion
18
+
19
+ if color_portion == 0
20
+ nil
21
+ else
22
+ RGB.new( values.map { |v| ( ( v - white_portion ) / color_portion ).round(6) } )
23
+ end
24
+ end
25
+
26
+ # Returns the portions of Ostwald full-color, white, and black, which constitute this color.
27
+ #
28
+ # The sum of these three numbers equals 1.
29
+ #
30
+ # #cwk is an alias for #ostwald_cwk.
31
+ #
32
+ # Based on:
33
+ # - Color for the Sciences, pp. 575–591
34
+ # - https://lirias.kuleuven.be/retrieve/306124 (PDF)
35
+ def ostwald_cwk(round: true)
36
+ [
37
+ color_portion = values.max - values.min,
38
+ white_portion = values.min,
39
+ 1 - color_portion - white_portion
40
+ ].map { |v| round ? v.round(8) : v }
41
+ end
42
+
43
+ alias cwk ostwald_cwk
44
+
45
+ end
@@ -0,0 +1,164 @@
1
+ GIMP Palette
2
+ Name: CSS Named Colors
3
+ #
4
+ # As per CSS Color Module Level 4, Editor's Draft, 19 August 2020.
5
+ # - source: https://drafts.csswg.org/css-color/#named-colors
6
+ #
7
+ # Notes:
8
+ # "Don't cite this document other than as work in progress."
9
+ #
10
+ # "CSS defines a large set of named colors, so that
11
+ # common colors can be written and read more easily."
12
+ #
13
+ # "[...] all of these keywords are ASCII case-insensitive."
14
+ #
15
+ # "The names resolve to colors in sRGB."
16
+ #
17
+ 240 248 255 aliceblue
18
+ 250 235 215 antiquewhite
19
+ 0 255 255 aqua
20
+ 127 255 212 aquamarine
21
+ 240 255 255 azure
22
+ 245 245 220 beige
23
+ 255 228 196 bisque
24
+ 0 0 0 black
25
+ 255 235 205 blanchedalmond
26
+ 0 0 255 blue
27
+ 138 43 226 blueviolet
28
+ 165 42 42 brown
29
+ 222 184 135 burlywood
30
+ 95 158 160 cadetblue
31
+ 127 255 0 chartreuse
32
+ 210 105 30 chocolate
33
+ 255 127 80 coral
34
+ 100 149 237 cornflowerblue
35
+ 255 248 220 cornsilk
36
+ 220 20 60 crimson
37
+ 0 255 255 cyan
38
+ 0 0 139 darkblue
39
+ 0 139 139 darkcyan
40
+ 184 134 11 darkgoldenrod
41
+ 169 169 169 darkgray
42
+ 0 100 0 darkgreen
43
+ 169 169 169 darkgrey
44
+ 189 183 107 darkkhaki
45
+ 139 0 139 darkmagenta
46
+ 85 107 47 darkolivegreen
47
+ 255 140 0 darkorange
48
+ 153 50 204 darkorchid
49
+ 139 0 0 darkred
50
+ 233 150 122 darksalmon
51
+ 143 188 143 darkseagreen
52
+ 72 61 139 darkslateblue
53
+ 47 79 79 darkslategray
54
+ 47 79 79 darkslategrey
55
+ 0 206 209 darkturquoise
56
+ 148 0 211 darkviolet
57
+ 255 20 147 deeppink
58
+ 0 191 255 deepskyblue
59
+ 105 105 105 dimgray
60
+ 105 105 105 dimgrey
61
+ 30 144 255 dodgerblue
62
+ 178 34 34 firebrick
63
+ 255 250 240 floralwhite
64
+ 34 139 34 forestgreen
65
+ 255 0 255 fuchsia
66
+ 220 220 220 gainsboro
67
+ 248 248 255 ghostwhite
68
+ 255 215 0 gold
69
+ 218 165 32 goldenrod
70
+ 128 128 128 gray
71
+ 0 128 0 green
72
+ 173 255 47 greenyellow
73
+ 128 128 128 grey
74
+ 240 255 240 honeydew
75
+ 255 105 180 hotpink
76
+ 205 92 92 indianred
77
+ 75 0 130 indigo
78
+ 255 255 240 ivory
79
+ 240 230 140 khaki
80
+ 230 230 250 lavender
81
+ 255 240 245 lavenderblush
82
+ 124 252 0 lawngreen
83
+ 255 250 205 lemonchiffon
84
+ 173 216 230 lightblue
85
+ 240 128 128 lightcoral
86
+ 224 255 255 lightcyan
87
+ 250 250 210 lightgoldenrodyellow
88
+ 211 211 211 lightgray
89
+ 144 238 144 lightgreen
90
+ 211 211 211 lightgrey
91
+ 255 182 193 lightpink
92
+ 255 160 122 lightsalmon
93
+ 32 178 170 lightseagreen
94
+ 135 206 250 lightskyblue
95
+ 119 136 153 lightslategray
96
+ 119 136 153 lightslategrey
97
+ 176 196 222 lightsteelblue
98
+ 255 255 224 lightyellow
99
+ 0 255 0 lime
100
+ 50 205 50 limegreen
101
+ 250 240 230 linen
102
+ 255 0 255 magenta
103
+ 128 0 0 maroon
104
+ 102 205 170 mediumaquamarine
105
+ 0 0 205 mediumblue
106
+ 186 85 211 mediumorchid
107
+ 147 112 219 mediumpurple
108
+ 60 179 113 mediumseagreen
109
+ 123 104 238 mediumslateblue
110
+ 0 250 154 mediumspringgreen
111
+ 72 209 204 mediumturquoise
112
+ 199 21 133 mediumvioletred
113
+ 25 25 112 midnightblue
114
+ 245 255 250 mintcream
115
+ 255 228 225 mistyrose
116
+ 255 228 181 moccasin
117
+ 255 222 173 navajowhite
118
+ 0 0 128 navy
119
+ 253 245 230 oldlace
120
+ 128 128 0 olive
121
+ 107 142 35 olivedrab
122
+ 255 165 0 orange
123
+ 255 69 0 orangered
124
+ 218 112 214 orchid
125
+ 238 232 170 palegoldenrod
126
+ 152 251 152 palegreen
127
+ 175 238 238 paleturquoise
128
+ 219 112 147 palevioletred
129
+ 255 239 213 papayawhip
130
+ 255 218 185 peachpuff
131
+ 205 133 63 peru
132
+ 255 192 203 pink
133
+ 221 160 221 plum
134
+ 176 224 230 powderblue
135
+ 128 0 128 purple
136
+ 102 51 153 rebeccapurple
137
+ 255 0 0 red
138
+ 188 143 143 rosybrown
139
+ 65 105 225 royalblue
140
+ 139 69 19 saddlebrown
141
+ 250 128 114 salmon
142
+ 244 164 96 sandybrown
143
+ 46 139 87 seagreen
144
+ 255 245 238 seashell
145
+ 160 82 45 sienna
146
+ 192 192 192 silver
147
+ 135 206 235 skyblue
148
+ 106 90 205 slateblue
149
+ 112 128 144 slategray
150
+ 112 128 144 slategrey
151
+ 255 250 250 snow
152
+ 0 255 127 springgreen
153
+ 70 130 180 steelblue
154
+ 210 180 140 tan
155
+ 0 128 128 teal
156
+ 216 191 216 thistle
157
+ 255 99 71 tomato
158
+ 64 224 208 turquoise
159
+ 238 130 238 violet
160
+ 245 222 179 wheat
161
+ 255 255 255 white
162
+ 245 245 245 whitesmoke
163
+ 255 255 0 yellow
164
+ 154 205 50 yellowgreen
@@ -15,16 +15,6 @@ class RGB
15
15
  self.b = ( ( v & 0x001f ) ) << 3
16
16
  end
17
17
 
18
- # Deprecated: this method will be removed in a future version.
19
- # Returns the color in 16-bit RGB565 format as a string of 0's and 1's.
20
- def rgb565_binary
21
- unless defined? @@warned_rgb565_binary_deprecation
22
- warn "Warning: 'rgb565_binary' has been deprecated and will be removed in a future version of redgreenblue."
23
- @@warned_rgb565_binary_deprecation = true
24
- end
25
- rgb565.bytes.reverse.map { |b| "%08b" % b }.join
26
- end
27
-
28
18
  # Creates a new RGB color from 16-bit RGB565 data.
29
19
  def self.rgb565(rgb565_string)
30
20
  c = self.new
@@ -1,7 +1,7 @@
1
1
  class RGB
2
2
 
3
3
  # redgreenblue version.
4
- VERSION = '0.9.0'
4
+ VERSION = '0.14.0'
5
5
 
6
6
  # Returns RGB::VERSION.
7
7
  def self.version
@@ -0,0 +1,34 @@
1
+ class RGB
2
+
3
+ # Prints details for the RGB object, using multiple lines.
4
+ def view
5
+ puts _inspect_view
6
+ end
7
+
8
+ alias v view
9
+
10
+ private
11
+
12
+ def _inspect_view
13
+ o = []
14
+ o << 3.times.map { terminal_background + " \e[0m "}
15
+ o << [ "#{_inspect_hex} ", '%-7.7s ' % color_space, ' ' ]
16
+
17
+ o << components.map { |c| c.terminal_background + " \e[0m " }
18
+ o << %w(R: G: B:)
19
+ o << values.map { |v| '%1.5f ' % v }
20
+ o << rgb.map { |v| '%3d ' % v }
21
+
22
+ o << %w(H: S: L:)
23
+ o << hsl.map { |v| v ? ('%7.3f ' % v) : ' - ' }
24
+ o << %w(H: S: B:)
25
+ o << hsb.map { |v| v ? ('%7.3f ' % v) : ' - ' }
26
+
27
+ o << 3.times.map { (ostwald_color ? ostwald_color.terminal_background + " \e[0m " : ' ') }
28
+ o << %w(C: W: K:)
29
+ o << ostwald_cwk.map { |v| '%1.3f ' % v }
30
+
31
+ o.transpose.map(&:join).join("\n")
32
+ end
33
+
34
+ end
@@ -1,5 +1,60 @@
1
1
  class RGB
2
2
 
3
+ #----------------------------------------------------------------------#
4
+ # Class Methods #
5
+ #----------------------------------------------------------------------#
6
+
7
+ class << self
8
+
9
+ # Returns CSS named colors, as per CSS Color Module Level 4.
10
+ #
11
+ # Optional selector argument can be:
12
+ # - String or Regexp (to select by name)
13
+ # - RGB color (to select by color)
14
+ # - Integer (to select by index).
15
+ # Selection by name (string or regular expression) is case-insensitive by default.
16
+ #
17
+ # @example No Selector
18
+ # # All colors
19
+ # RGB.css
20
+ #
21
+ # # Pastels
22
+ # RGB.css.select { |c| c.ostwald_cwk[1] > 0.6 }
23
+ # @example Select by Name
24
+ # # Exact name
25
+ # RGB.css 'pink'
26
+ #
27
+ # # Regular expression
28
+ # RGB.css /pink|rose/
29
+ #
30
+ # @example Select by RGB color
31
+ # RGB.css RGB.hex('0ff')
32
+ def css(selector=nil)
33
+ @@css ||= load_gpl file: ( File.join File.dirname(__FILE__), 'palettes', 'css.gpl' ), freeze: true
34
+ case selector
35
+ when NilClass
36
+ @@css
37
+ when String
38
+ n = selector.downcase
39
+ @@css.select { |c| c.name == n }.first
40
+ when Regexp
41
+ r = Regexp.new selector.source, Regexp::IGNORECASE
42
+ @@css.select { |c| c.name =~ r }
43
+ when Integer
44
+ @@css[selector]
45
+ when self
46
+ @@css.select { |c| c == selector }
47
+ else
48
+ raise ArgumentError, 'Unsupported selector'
49
+ end
50
+ end
51
+
52
+ end
53
+
54
+ #----------------------------------------------------------------------#
55
+ # Instance Methods #
56
+ #----------------------------------------------------------------------#
57
+
3
58
  # Returns the object's RGB value in hexadecimal notation as used in CSS.
4
59
  #
5
60
  # Shortens to 3 digits when possible.
@@ -7,4 +62,48 @@ class RGB
7
62
  "##{hex true}"
8
63
  end
9
64
 
65
+ # Returns the names of CSS named colors identical to this color.
66
+ # @example
67
+ # RGB.hex('f0f').css_names
68
+ def css_names
69
+ RGB.css(self).map &:name
70
+ end
71
+
72
+ # Returns the color's relative luminance, as defined by the Web Content Accessibility Guidelines (WCAG) 2.0.
73
+ #
74
+ # This is different from the Y component of CIE 1931 XYZ.
75
+ #
76
+ # Based on:
77
+ # - https://www.w3.org/TR/WCAG20/#relativeluminancedef
78
+ def wcag20_luminance(round: true)
79
+ if color_space == 'sRGB'
80
+ values.map { |v|
81
+ if v <= 0.03928
82
+ v / 12.92
83
+ else
84
+ ( ( v + 0.055 ) / 1.055 ) ** 2.4
85
+ end
86
+ }.zip( [0.2126, 0.7152, 0.0722] ).map { |c,f|
87
+ c * f
88
+ }.inject(:+).instance_eval { |v| round ? v.round(8) : v }
89
+ else
90
+ raise "can not calculate luminance for color space '#{color_space}'"
91
+ end
92
+ end
93
+
94
+ # Returns the contrast ratio for this color and another color, as defined by the Web Content Accessibility Guidelines (WCAG) 2.0.
95
+ #
96
+ # Based on:
97
+ # - https://www.w3.org/TR/WCAG20/#contrast-ratiodef
98
+ def wcag20_contrast_ratio(another, round: true)
99
+ luminances = [
100
+ wcag20_luminance(round: false),
101
+ another.wcag20_luminance(round: false)
102
+ ].sort.reverse
103
+
104
+ contrast_ratio = ( luminances[0] + 0.05 ) / ( luminances[1] + 0.05 )
105
+
106
+ round ? contrast_ratio.round(8) : contrast_ratio
107
+ end
108
+
10
109
  end