redgreenblue 0.7.0 → 0.8.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9dea62bd74822100097e661284f2d44164a1be23ee0f81acdc778c182f0939ec
4
- data.tar.gz: baa4c5ab0b3a367841ee18d94131ad4077661d515edb29939ed661175b479ee1
3
+ metadata.gz: 766113ae54ad00c066d264e8bd8d63610f5347e75d95aee3c34bacac0b027a99
4
+ data.tar.gz: a91d7d49e36ebfc29328e32c2aa67df908e4fbc9d36c4ec957e1e6d8ed3220b7
5
5
  SHA512:
6
- metadata.gz: 81808e69a0aadb6ea54cb291fd682c1949e2178df1c31954256167552f12b990ef825561689a958cb533144c25d31852785ebcebe9d07ddb5684b3b0dfcd26ba
7
- data.tar.gz: 62370184d5b291081bd8e7a1f698647d961fd4c98525677821950f59e58e5536473d5f4c0e87da53109866e875caf94fc578fdf14d4de602d50fd0085d4fe6d9
6
+ metadata.gz: 587d547ca6139b84ef36f8064a768aee1cdb3f5618f4f03c9ab606df477ad6ebffe82b00837fe55b06fcf2ba6275a1d85484f758394755567b1aab81351bf1df
7
+ data.tar.gz: e5203156810f3f577bbe20de7d862f96518db292b1f848778dc2c9dc5223b16c9e15e6effc2e08ed4dba655891805873fdf95cda511c5a533f87462200401746
@@ -10,14 +10,18 @@ require 'redgreenblue/48bit'
10
10
  require 'redgreenblue/hex'
11
11
 
12
12
  require 'redgreenblue/hsl_hsv'
13
+ require 'redgreenblue/cie'
13
14
 
15
+ require 'redgreenblue/inspect'
14
16
  require 'redgreenblue/lazy'
15
- require 'redgreenblue/nice'
16
17
 
17
18
  require 'redgreenblue/rgb565'
18
19
  require 'redgreenblue/bgr24bit'
19
20
  require 'redgreenblue/gif'
21
+ require 'redgreenblue/terminal'
22
+ require 'redgreenblue/web'
20
23
 
24
+ require 'redgreenblue/mix'
21
25
  require 'redgreenblue/misc'
22
26
  require 'redgreenblue/random'
23
27
 
@@ -51,4 +51,19 @@ class RGB
51
51
  c
52
52
  end
53
53
 
54
+ # Calls the given block for each 24-bit RGB color (from black to white), passing the color as an RGB object.
55
+ #
56
+ # Returns the number of iterations.
57
+ def self.each_24bit_color
58
+ range = 0..255
59
+ range.each do |r|
60
+ range.each do |g|
61
+ range.each do |b|
62
+ yield self.rgb(r,g,b)
63
+ end
64
+ end
65
+ end
66
+ range.size ** 3
67
+ end
68
+
54
69
  end
@@ -1,41 +1,73 @@
1
1
  class RGB
2
2
 
3
- attr_reader :red, :green, :blue
4
-
5
3
  def initialize(*a)
6
4
  self.values = a.any? ? a : [ 0.5, 0.5, 0.5 ]
7
5
  end
8
6
 
9
- def red=(n)
10
- @red = limit(n)
7
+ # Returns the color space.
8
+ #
9
+ # Currently always 'sRGB'.
10
+ def color_space
11
+ @color_space ||= 'sRGB'
12
+ end
13
+
14
+ # Returns the red component as a value between 0 and 1.
15
+ def red
16
+ @red
17
+ end
18
+
19
+ # Returns the green component as a value between 0 and 1.
20
+ def green
21
+ @green
22
+ end
23
+
24
+ # Returns the blue component as a value between 0 and 1.
25
+ def blue
26
+ @blue
27
+ end
28
+
29
+ # Sets the red component to a value between 0 and 1.
30
+ #
31
+ # Values outside the range 0..1 will be clipped.
32
+ def red=(value)
33
+ @red = limit(value)
11
34
  end
12
35
 
13
- def green=(n)
14
- @green = limit(n)
36
+ # Sets the green component to a value between 0 and 1.
37
+ #
38
+ # Values outside the range 0..1 will be clipped.
39
+ def green=(value)
40
+ @green = limit(value)
15
41
  end
16
42
 
17
- def blue=(n)
18
- @blue = limit(n)
43
+ # Sets the blue component to a value between 0 and 1.
44
+ #
45
+ # Values outside the range 0..1 will be clipped.
46
+ def blue=(value)
47
+ @blue = limit(value)
19
48
  end
20
49
 
50
+ # Returns the red, green, and blue components as three values between 0 and 1.
21
51
  def values
22
52
  [ red, green, blue ]
23
53
  end
24
54
 
25
55
  alias to_a values
26
56
 
57
+ # Sets the red, green, and blue components using three values between 0 and 1.
58
+ #
59
+ # Values outside the range 0..1 will be clipped.
27
60
  def values=(*a)
28
61
  self.red, self.green, self.blue = a.flatten
29
62
  end
30
63
 
31
- # Returns true if this object and an other object represent exactly the same color. Otherwise returns false.
64
+ # Returns true if this object and another object represent exactly the same color. Otherwise returns false.
32
65
  def ==(other)
33
66
  ( self.class == other.class ) && ( self.values == other.values )
34
67
  end
35
68
 
36
- # Returns a sorted hash of 3 key/value pairs
37
- # for red, green and blue,
38
- # sorted in order of decreasing value
69
+ # Returns a sorted hash of 3 key/value pairs for red, green and blue,
70
+ # sorted in order of decreasing value.
39
71
  def to_h
40
72
  ([:red, :green, :blue].zip values).sort_by {
41
73
  |k,v| [-v,[:red, :green, :blue].index(k)]
@@ -44,7 +76,7 @@ class RGB
44
76
 
45
77
  private
46
78
 
47
- # limit to 0..1
79
+ # limits to range 0..1
48
80
  def limit(n)
49
81
  n <= 0 ? 0.0 : n >= 1 ? 1.0 : n
50
82
  end
@@ -1,16 +1,16 @@
1
1
  class RGB
2
2
 
3
- # bgr 24-bit methods (as used by BMP bitmaps)
4
-
3
+ # Returns a 3-byte string containing the object's color in BGR24 format.
5
4
  def bgr24
6
5
  [b, g, r].pack('C3')
7
6
  end
8
7
 
9
- def bgr24=(s)
10
- self.b, self.g, self.r = s.unpack('C3')
8
+ # Sets red, green, and blue using BGR24 data (a 3-byte string).
9
+ def bgr24=(bgr_string)
10
+ self.b, self.g, self.r = bgr_string.unpack('C3')
11
11
  end
12
12
 
13
- # factory method
13
+ # Creates a new RGB object from BGR24 data (a 3-byte string).
14
14
  def self.bgr24(bgr)
15
15
  c = self.new
16
16
  c.bgr24 = bgr
@@ -0,0 +1,62 @@
1
+ class RGB
2
+
3
+ # Returns CIE 1931 XYZ values for the RGB object.
4
+ #
5
+ # Based on:
6
+ # - http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html
7
+ # - https://en.wikipedia.org/wiki/CIE_1931_color_space
8
+ # sRGB to XYZ matrix for D65 reference white by Bruce Lindbloom:
9
+ # - http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
10
+ def cie_xyz
11
+ r, g, b = expanded_srgb_values
12
+ [
13
+ r * 0.4124564 + g * 0.3575761 + b * 0.1804375,
14
+ r * 0.2126729 + g * 0.7151522 + b * 0.0721750,
15
+ r * 0.0193339 + g * 0.1191920 + b * 0.9503041
16
+ ].map { |v| v.round(6) }
17
+ end
18
+
19
+ alias xyz cie_xyz
20
+
21
+ # Returns CIE 1931 xyY values for the RGB object.
22
+ #
23
+ # Based on:
24
+ # - https://en.wikipedia.org/wiki/CIE_1931_color_space
25
+ # - http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_xyY.html
26
+ # - https://ninedegreesbelow.com/photography/xyz-rgb.html
27
+ def cie_xyy
28
+ x, y, z = xyz
29
+ [
30
+ x / ( x + y + z ),
31
+ y / ( x + y + z ),
32
+ y
33
+ ].map { |v| v.round(6) }
34
+ end
35
+
36
+ alias xyy cie_xyy
37
+
38
+ # Returns CIE 1931 xy values for the RGB object.
39
+ def cie_xy
40
+ cie_xyy[0..1]
41
+ end
42
+
43
+ alias xy cie_xy
44
+
45
+ private
46
+
47
+ # Returns gamma-expanded (inverse-companded) RGB values for sRGB.
48
+ #
49
+ # Based on:
50
+ # - https://en.wikipedia.org/wiki/SRGB
51
+ # - http://www.brucelindbloom.com/Eqn_RGB_to_XYZ.html
52
+ def expanded_srgb_values
53
+ values.map { |v|
54
+ if v <= 0.04045
55
+ v / 12.92
56
+ else
57
+ ( ( v + 0.055 ) / 1.055 ) ** 2.4
58
+ end
59
+ }
60
+ end
61
+
62
+ end
@@ -1,35 +1,66 @@
1
1
  class RGB
2
2
 
3
+ # Returns a 6-digit hexadecimal string representing the object's red, green, and blue components as 8-bit values.
4
+ #
5
+ # If shorthand is true, returns 3-digit shorthand if possible.
3
6
  def hex(shorthand=false)
4
7
  if shorthand
5
- RGB.hex_shorthand hexadecimal
8
+ RGB.hex_shorthand hex6
6
9
  else
7
- hexadecimal
10
+ hex6
8
11
  end
9
12
  end
10
13
 
11
- def hex=(s)
12
- if ( s =~ /^(#?)(\h\h)(\h\h)(\h\h)$/ ) # 6-digit hex
13
- self.rgb = [ $2.to_i(16), $3.to_i(16), $4.to_i(16) ]
14
- elsif ( s =~ /^(#?)(\h)(\h)(\h)$/ ) # 3-digit hex
15
- self.rgb = [ ($2*2).to_i(16), ($3*2).to_i(16), ($4*2).to_i(16) ]
14
+ # Sets red, green, and blue using a 6- or 3-digit hexadecimal string.
15
+ #
16
+ # The string may include a '#' prefix.
17
+ def hex=(hex_string)
18
+ if rgb = RGB.hex_to_rgb(hex_string)
19
+ self.rgb = rgb
20
+ else
21
+ raise ArgumentError, "'#{hex_string}' is not a usable hexadecimal string"
22
+ end
23
+ end
24
+
25
+
26
+ # Class methods
27
+
28
+
29
+ # Creates a new object from a 6- or 3-digit hexadecimal string representing red, green, and blue.
30
+ #
31
+ # The string may include a '#' prefix.
32
+ def self.hex(hex_string)
33
+ if rgb = RGB.hex_to_rgb(hex_string)
34
+ self.rgb rgb
35
+ else
36
+ raise ArgumentError, "'#{hex_string}' is not a usable hexadecimal string"
16
37
  end
17
38
  end
18
39
 
19
- # factory method
20
- def self.hex(s)
21
- c = self.new
22
- c.hex = s
23
- c
40
+ # Returns a 3-digit shorthand version of a 6-digit hexadecimal string.
41
+ #
42
+ # If a shorthand version is not possible, returns the original string.
43
+ def self.hex_shorthand(hex_string)
44
+ hex_string.sub( /^(#?)(\h)\2(\h)\3(\h)\4$/, '\1\2\3\4' )
24
45
  end
25
46
 
26
- def self.hex_shorthand(h)
27
- h.sub( /^(#?)(\h)\2(\h)\3(\h)\4$/, '\1\2\3\4' )
47
+ # Parses a 6- or 3-digit hexadecimal string.
48
+ # Returns three integers in the range 0..255, or nil if not successful.
49
+ #
50
+ # The string may include a '#' prefix.
51
+ def self.hex_to_rgb(hex_string)
52
+ if hex_string =~ /^(#?)(\h\h)(\h\h)(\h\h)$/
53
+ [$2, $3, $4].map { |h| h.to_i(16) }
54
+ elsif hex_string =~ /^(#?)(\h)(\h)(\h)$/
55
+ [$2, $3, $4].map { |h| (h*2).to_i(16) }
56
+ else
57
+ nil
58
+ end
28
59
  end
29
60
 
30
61
  private
31
62
 
32
- def hexadecimal
63
+ def hex6
33
64
  '%02x%02x%02x' % [ r, g, b ]
34
65
  end
35
66
 
@@ -0,0 +1,51 @@
1
+ class RGB
2
+
3
+ private
4
+
5
+ def _inspect_default(prefix='RGB')
6
+ "#{prefix} ##{hex} (red=%1.5f green=%1.5f blue=%1.5f)" % [red, green, blue]
7
+ end
8
+
9
+ def _inspect_hex
10
+ "##{hex}"
11
+ end
12
+
13
+ def _inspect_swatch
14
+ terminal_background + " \e[0m"
15
+ end
16
+
17
+ def _inspect_simple
18
+ _inspect_default _inspect_swatch
19
+ end
20
+
21
+ public
22
+
23
+ def inspect
24
+ send "_inspect_#{self.class.style}"
25
+ end
26
+
27
+ def to_s
28
+ _inspect_default
29
+ end
30
+
31
+ # Returns the base inspect style, dependent on the COLORTERM environment variable.
32
+ def self.base_style
33
+ ENV['COLORTERM'] == 'truecolor' ? 'simple' : 'default'
34
+ end
35
+
36
+ # Returns the current inspect style.
37
+ def self.style
38
+ @@style ||= base_style
39
+ end
40
+
41
+ # Returns a list of all available inspect styles.
42
+ def self.styles
43
+ ( self.instance_methods + self.private_instance_methods ).grep( /^_inspect_(.*)/ ) { $1 }.sort
44
+ end
45
+
46
+ # Selects an inspect style.
47
+ def self.style=(s)
48
+ @@style = styles.grep( /^#{s.to_s.downcase}/ ).first || style
49
+ end
50
+
51
+ end
@@ -1,60 +1,27 @@
1
1
  class RGB
2
2
 
3
- # Mix
4
-
5
- # Mix with second RGB color.
6
- # p denotes portion of the mixed-in color to be used.
7
- # p=0 delivers pure original color (no change),
8
- # p=1 delivers pure mixed-in color.
9
-
10
- def mix!(color,p=0.5)
11
- self.values = mix_values(color.values, p)
12
- self
13
- end
14
-
15
- def mix(color,p=0.5)
16
- RGB.new mix_values(color.values, p)
17
- end
18
-
19
- # Invert
20
-
3
+ # Inverts the object's color.
21
4
  def invert!
22
- self.values = values.map { |v| 1-v }
5
+ self.values = values.map { |v| 1 - v }
23
6
  self
24
7
  end
25
8
 
9
+ # Creates a new RGB object with the inverted color of this RGB object.
26
10
  def invert
27
11
  dup.invert!
28
12
  end
29
13
 
30
- # Mix with white
31
-
32
- def whiten!(p)
33
- mix!(RGB.white, p)
34
- end
35
-
36
- def whiten(p)
37
- mix(RGB.white, p)
38
- end
39
-
40
- # Mix with black
41
-
42
- def blacken!(p)
43
- mix!(RGB.black, p)
14
+ # Returns an array of RGB objects for all possible ways in which the red, green, and blue values of this object can be exchanged.
15
+ #
16
+ # Example: RGB.red.permutation returns [ RGB.red, RGB.green, RGB.blue ]
17
+ # See also: shuffle
18
+ def permutation
19
+ values.permutation.to_a.uniq.map { |v| RGB.new v }
44
20
  end
45
21
 
46
- def blacken(p)
47
- mix(RGB.black, p)
22
+ # Returns an array of three RGB objects, for the red, green, and blue components of this object.
23
+ def components
24
+ [ RGB.new(red,0,0), RGB.new(0,green,0), RGB.new(0,0,blue) ]
48
25
  end
49
26
 
50
- private
51
-
52
- def mix_values(v, p)
53
- raise(ArgumentError, "Portion '#{p}' not in range (0..1)") unless (0..1).include? p
54
- [
55
- ( red * (1-p) ) + ( v[0] * p ),
56
- ( green * (1-p) ) + ( v[1] * p ),
57
- ( blue * (1-p) ) + ( v[2] * p )
58
- ]
59
- end
60
27
  end
@@ -0,0 +1,44 @@
1
+ class RGB
2
+
3
+ # Changes the object's color by mixing it with a portion of another RGB color.
4
+ def mix!(another,portion=0.5)
5
+ self.values = mix_values(another.values, portion)
6
+ self
7
+ end
8
+
9
+ # Creates a new RGB object by mixing this object's color with a portion of another RGB color.
10
+ def mix(another,portion=0.5)
11
+ RGB.new mix_values(another.values, portion)
12
+ end
13
+
14
+ # Changes the object's color by mixing it with a portion of white.
15
+ def whiten!(portion=0.5)
16
+ mix!(RGB.white, portion)
17
+ end
18
+
19
+ # Creates a new RGB object by mixing this object's color with a portion of white.
20
+ def whiten(portion=0.5)
21
+ mix(RGB.white, portion)
22
+ end
23
+
24
+ # Changes the object's color by mixing it with a portion of black.
25
+ def blacken!(portion=0.5)
26
+ mix!(RGB.black, portion)
27
+ end
28
+
29
+ # Creates a new RGB object by mixing this object's color with a portion of black.
30
+ def blacken(portion=0.5)
31
+ mix(RGB.black, portion)
32
+ end
33
+
34
+ private
35
+
36
+ def mix_values(some_values, portion)
37
+ raise(ArgumentError, "Portion '#{portion}' not in range (0..1)") unless (0..1).include? portion
38
+ [
39
+ ( red * (1 - portion) ) + ( some_values[0] * portion ),
40
+ ( green * (1 - portion) ) + ( some_values[1] * portion ),
41
+ ( blue * (1 - portion) ) + ( some_values[2] * portion )
42
+ ]
43
+ end
44
+ end
@@ -1,9 +1,13 @@
1
+ # Optional support for Philips Hue lights.
2
+
3
+ # Automatically load core RGB class before loading options.
4
+ require 'redgreenblue'
5
+
1
6
  class RGB
2
7
 
3
8
  # Returns the arguments required by the Philips Hue API to set a light to this RGB object's hue, saturation and brightness (HSB).
4
9
  #
5
- # When formatted as JSON, this hash can be used
6
- # directly to set a light's state.
10
+ # When formatted as JSON, this hash can be used directly to set a light's state.
7
11
  def to_philips_hue_api_hsb_arguments(black_off=true)
8
12
  my_hsb = hsb
9
13
 
@@ -31,8 +31,15 @@ class RGB
31
31
  # Standard Additions -> User Interaction -> choose color
32
32
  def self.mac_choose(color)
33
33
 
34
+ app = case ENV['TERM_PROGRAM']
35
+ when /iTerm\.app/
36
+ 'iTerm'
37
+ else
38
+ 'Terminal'
39
+ end
40
+
34
41
  script = <<~ENDSCRIPT
35
- tell application "Terminal"
42
+ tell application "#{app}"
36
43
  try
37
44
  return choose color default color { #{color[0]}, #{color[1]}, #{color[2]} }
38
45
  on error
@@ -6,6 +6,11 @@ class RGB
6
6
  self
7
7
  end
8
8
 
9
+ # Creates a new RGB object with this object's red, green, and blue values shuffled.
10
+ def shuffle
11
+ RGB.new values.shuffle
12
+ end
13
+
9
14
  # Assigns random values to red, green, and blue.
10
15
  def randomize!
11
16
  self.values = Kernel::rand, Kernel::rand, Kernel::rand
@@ -0,0 +1,19 @@
1
+ class RGB
2
+
3
+ # With help from:
4
+ # - https://gist.github.com/XVilka/8346728
5
+ # - https://unix.stackexchange.com/questions/404414
6
+
7
+ # Returns the ANSI escape sequence required to set the foreground color on a terminal to this color.
8
+ # Only works on terminals that support 24-bit colors, so-called "true color".
9
+ def terminal_foreground
10
+ "\e[38;2;%d;%d;%dm" % rgb
11
+ end
12
+
13
+ # Returns the ANSI escape sequence required to set the background color on a terminal to this color.
14
+ # Only works on terminals that support 24-bit colors, so-called "true color".
15
+ def terminal_background
16
+ "\e[48;2;%d;%d;%dm" % rgb
17
+ end
18
+
19
+ end
@@ -1,3 +1,3 @@
1
1
  class RGB
2
- VERSION = '0.7.0'
2
+ VERSION = '0.8.0'
3
3
  end
@@ -0,0 +1,10 @@
1
+ class RGB
2
+
3
+ # Returns the object's RGB value in hexadecimal notation as used in CSS.
4
+ #
5
+ # Shortens to 3 digits when possible.
6
+ def css_hex
7
+ "##{hex true}"
8
+ end
9
+
10
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redgreenblue
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - lllist.eu
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-11-11 00:00:00.000000000 Z
11
+ date: 2019-12-20 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email:
@@ -21,18 +21,22 @@ files:
21
21
  - lib/redgreenblue/48bit.rb
22
22
  - lib/redgreenblue/base.rb
23
23
  - lib/redgreenblue/bgr24bit.rb
24
+ - lib/redgreenblue/cie.rb
24
25
  - lib/redgreenblue/gif.rb
25
26
  - lib/redgreenblue/hex.rb
26
27
  - lib/redgreenblue/hsl_hsv.rb
28
+ - lib/redgreenblue/inspect.rb
27
29
  - lib/redgreenblue/lazy.rb
28
30
  - lib/redgreenblue/misc.rb
29
- - lib/redgreenblue/nice.rb
31
+ - lib/redgreenblue/mix.rb
30
32
  - lib/redgreenblue/opt/philipshue.rb
31
33
  - lib/redgreenblue/os.rb
32
34
  - lib/redgreenblue/os/mac.rb
33
35
  - lib/redgreenblue/random.rb
34
36
  - lib/redgreenblue/rgb565.rb
37
+ - lib/redgreenblue/terminal.rb
35
38
  - lib/redgreenblue/version.rb
39
+ - lib/redgreenblue/web.rb
36
40
  homepage: https://github.com/lllisteu/redgreenblue
37
41
  licenses:
38
42
  - MIT
@@ -52,8 +56,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
52
56
  - !ruby/object:Gem::Version
53
57
  version: '0'
54
58
  requirements: []
55
- rubygems_version: 3.0.3
59
+ rubygems_version: 3.0.6
56
60
  signing_key:
57
61
  specification_version: 4
58
- summary: A simple Ruby library for handling RGB colors
62
+ summary: A simple Ruby library for handling RGB colors.
59
63
  test_files: []
@@ -1,9 +0,0 @@
1
- class RGB
2
-
3
- def inspect
4
- "RGB ##{hex} (red=%1.5f green=%1.5f blue=%1.5f)" % [red, green, blue]
5
- end
6
-
7
- alias to_s inspect
8
-
9
- end