redgreenblue 0.11.0 → 0.15.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: dc4e866d75637857fb5a4b27b77829e20f488e321fa287b73a5d6d9c21d194a9
4
- data.tar.gz: e3f9e875b0a8893bd21a6cd503702881833f54873557f84c4cf4776338294668
3
+ metadata.gz: 0e6715019b7628fa8a5027295b3fb5e617f829d494eda1c4a0dad495adca6e44
4
+ data.tar.gz: 745987a3b640392f140bc6f7d3d18575f815a75a00d96162a0a9f3cdba64cc71
5
5
  SHA512:
6
- metadata.gz: 94b96125e65443d7ceb66cfabf9ba6b0681bfc51046b8d308e86d0904a58a7f745f6ea159a040ee79dcb9713ace9adbc416a5705c4b2ebb85333bf09f0dd9a43
7
- data.tar.gz: f3e0bd4c0cdcd432dd50fc518f1d2062c66ac907f55b3235405589b2d797791c48b3d62284ae665a8fc4d60c4209ce0b3d46d07a459e15d2fa261d9b1aa8df1d
6
+ metadata.gz: 16538077413e35eeeae4d4da51bfd6eca7d7d3c9beba338df99742278762aa243dce8262fd9f95276154881dbdafe5ab26e4282ac2e485d82337f69a3bb61679
7
+ data.tar.gz: 5dabac01d2f52b4cd187f4248a4d3a520e76ff5c419ead409468bb01b14935b67b528375fca2ad338d79f8257c74489511609da792a88f52f4eb8de670377cd6
@@ -8,7 +8,7 @@ class RGB
8
8
  #
9
9
  # Currently always 'sRGB'.
10
10
  def color_space
11
- @color_space ||= 'sRGB'
11
+ 'sRGB'
12
12
  end
13
13
 
14
14
  # Returns the red component as a value between 0 and 1.
@@ -5,15 +5,18 @@ class RGB
5
5
  # Based on:
6
6
  # - http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html
7
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
8
+ # sRGB to XYZ matrix for D65 reference white calculated with Javascript by Bruce Lindbloom:
9
+ # - http://www.brucelindbloom.com/ColorCalculator.html
10
+ def cie_xyz(round: true)
11
11
  r, g, b = linear_values
12
+
12
13
  [
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) }
14
+
15
+ r * 0.4124_5643_9090 + g * 0.3575_7607_7644 + b * 0.1804_3748_3266,
16
+ r * 0.2126_7285_1406 + g * 0.7151_5215_5288 + b * 0.0721_7499_3307,
17
+ r * 0.0193_3389_5582 + g * 0.1191_9202_5881 + b * 0.9503_0407_8536
18
+
19
+ ].map { |v| round ? v.round(8) : v }
17
20
  end
18
21
 
19
22
  alias xyz cie_xyz
@@ -25,12 +28,15 @@ class RGB
25
28
  # - http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_xyY.html
26
29
  # - https://ninedegreesbelow.com/photography/xyz-rgb.html
27
30
  def cie_xyy
28
- x, y, z = xyz
31
+ x, y, z = cie_xyz(round: false)
32
+
29
33
  [
34
+
30
35
  x / ( x + y + z ),
31
36
  y / ( x + y + z ),
32
37
  y
33
- ].map { |v| v.round(6) }
38
+
39
+ ].map { |v| v.round(8) }
34
40
  end
35
41
 
36
42
  alias xyy cie_xyy
@@ -0,0 +1,105 @@
1
+ class RGB
2
+
3
+ # Returns CIE 1976 L*a*b* (CIELAB) values for the RGB object.
4
+ def cie_lab(round: true)
5
+ cie_lab_luv(round: round, type: :lab)
6
+ end
7
+
8
+ alias lab cie_lab
9
+
10
+ # Returns CIE 1976 LCHab values for the RGB object, derived from L*a*b* (CIELAB).
11
+ #
12
+ # When C is 0, H is nil.
13
+ def cie_lch_ab
14
+ cie_lch_ab_uv(type: :lab)
15
+ end
16
+
17
+ # Returns CIE 1976 L*u*v* (CIELUV) values for the RGB object.
18
+ def cie_luv(round: true)
19
+ cie_lab_luv(round: round, type: :luv)
20
+ end
21
+
22
+ alias luv cie_luv
23
+
24
+ # Returns CIE 1976 LCHuv values for the RGB object, derived from L*u*v* (CIELUV).
25
+ #
26
+ # When C is 0, H is nil.
27
+ def cie_lch_uv
28
+ cie_lch_ab_uv(type: :luv)
29
+ end
30
+
31
+ # Returns the difference between this color and another color, according to the CIE 1976 delta E formula.
32
+ #
33
+ # Based on:
34
+ # - http://www.brucelindbloom.com/Eqn_DeltaE_CIE76.html
35
+ # - https://en.wikipedia.org/wiki/Color_difference
36
+ def delta_e_cie_1976(another)
37
+ l , a , b = cie_lab(round: false)
38
+ l2, a2, b2 = another.cie_lab(round: false)
39
+
40
+ Math.sqrt( (l - l2) ** 2 + (a - a2) ** 2 + (b - b2) ** 2 ).round(8)
41
+ end
42
+
43
+ alias de76 delta_e_cie_1976
44
+
45
+ private
46
+
47
+ # Returns either CIE 1976 L*a*b* (CIELAB) or CIE 1976 L*u*v* (CIELUV) values for the RGB object.
48
+ #
49
+ # L*a*b* formula based on:
50
+ # - http://www.brucelindbloom.com/Eqn_XYZ_to_Lab.html
51
+ # - https://en.wikipedia.org/wiki/CIELAB_color_space
52
+ # With peeking at:
53
+ # - https://github.com/halostatue/color/blob/master/lib/color/rgb.rb
54
+ #
55
+ # L*u*v* formula based on:
56
+ # - http://www.brucelindbloom.com/Eqn_XYZ_to_Luv.html
57
+ # - https://en.wikipedia.org/wiki/CIELUV
58
+ def cie_lab_luv(round: true, type: :lab)
59
+ x , y , z = cie_xyz(round: false)
60
+ xr, yr, zr = RGB.white.cie_xyz(round: false)
61
+
62
+ f = [ x / xr, y / yr, z / zr ].map { |v|
63
+ if v > ( 216.0 / 24389 )
64
+ Math.cbrt v
65
+ else
66
+ ( 24389.0 / 27 * v + 16 ) / 116.0
67
+ end
68
+ }
69
+
70
+ if type == :luv
71
+ [
72
+ l = 116 * f[1] - 16,
73
+ 13 * l * ( ( 4 * x ) / ( x + 15 * y + 3 * z ) - ( 4 * xr ) / ( xr + 15 * yr + 3 * zr ) ),
74
+ 13 * l * ( ( 9 * y ) / ( x + 15 * y + 3 * z ) - ( 9 * yr ) / ( xr + 15 * yr + 3 * zr ) )
75
+ ]
76
+ else
77
+ [
78
+ 116 * f[1] - 16,
79
+ 500 * (f[0] - f[1]),
80
+ 200 * (f[1] - f[2])
81
+ ]
82
+ end.map { |v| v.nan? ? 0.0 : ( round ? v.round(8) : v ) }
83
+ end
84
+
85
+ # Returns either CIE 1976 LCHab or CIE 1976 LCHuv values for the RGB object.
86
+ #
87
+ # Based on:
88
+ # - http://www.brucelindbloom.com/Eqn_Lab_to_LCH.html
89
+ # - http://www.brucelindbloom.com/Eqn_Luv_to_LCH.html
90
+ # - https://en.wikipedia.org/wiki/CIELAB_color_space
91
+ def cie_lch_ab_uv(type: :lab)
92
+ if type == :luv
93
+ l, v1, v2 = cie_luv(round: false)
94
+ else
95
+ l, v1, v2 = cie_lab(round: false)
96
+ end
97
+
98
+ [
99
+ l.round(8),
100
+ c = Math.hypot(v1, v2).round(8),
101
+ c == 0 ? nil : ( Math.atan2(v2, v1) * 180.0 / Math::PI ).modulo(360).round(8)
102
+ ]
103
+ end
104
+
105
+ end
@@ -0,0 +1,55 @@
1
+ class RGB
2
+
3
+ # Returns the difference between this (reference) color and another color, according to the CIE 1994 delta E formula.
4
+ #
5
+ # By default uses parameters for use in graphic arts, and reference conditions.
6
+ # Parameters (k1, k2, kl, kc, kh) can be individually overriden for different applications and for variations in conditions.
7
+ #
8
+ # Based on:
9
+ # - http://www.brucelindbloom.com/Eqn_DeltaE_CIE94.html
10
+ # - https://archive.org/details/gov.law.cie.15.2004
11
+ # - https://en.wikipedia.org/wiki/Color_difference
12
+ def delta_e_cie_1994(another, k1: 0.045, k2: 0.015, kl: 1, kc: 1, kh: 1)
13
+
14
+ l , a , b = cie_lab(round: false)
15
+ l2, a2, b2 = another.cie_lab(round: false)
16
+
17
+ c = Math.hypot(a , b )
18
+ c2 = Math.hypot(a2, b2)
19
+
20
+ da = a - a2
21
+ db = b - b2
22
+ dc = c - c2
23
+
24
+ dh2 = (da ** 2) + (db ** 2) - (dc ** 2)
25
+ dl = l - l2
26
+
27
+ sl = 1
28
+ sc = 1 + k1 * c
29
+ sh = 1 + k2 * c
30
+
31
+ Math.sqrt(
32
+ ( (dl / ( kl*sl)) ** 2 ) +
33
+ ( (dc / ( kc*sc)) ** 2 ) +
34
+ ( dh2 / ((kh*sh) ** 2) )
35
+ ).round(6)
36
+
37
+ end
38
+
39
+ alias de94 delta_e_cie_1994
40
+
41
+ # Returns the difference between this (reference) color and another color, according to the CIE 1994 delta E formula.
42
+ #
43
+ # For use in graphic arts, under reference conditions.
44
+ def de94g(another)
45
+ delta_e_cie_1994(another)
46
+ end
47
+
48
+ # Returns the difference between this (reference) color and another color, according to the CIE 1994 delta E formula.
49
+ #
50
+ # For use with textiles, under reference conditions.
51
+ def de94t(another)
52
+ delta_e_cie_1994(another, k1: 0.048, k2: 0.014, kl: 2)
53
+ end
54
+
55
+ end
@@ -1,30 +1,94 @@
1
1
  class RGB
2
2
 
3
- ########################################################################
4
- # Class methods #
5
- ########################################################################
3
+ #----------------------------------------------------------------------#
4
+ # Class Methods #
5
+ #----------------------------------------------------------------------#
6
6
 
7
7
  class << self
8
8
 
9
- private
9
+ # Creates a new RGB object from a line of gpl (Gimp color palette) input. Returns nil if not successful.
10
+ #
11
+ # @example
12
+ # RGB.gpl "255 153 204\tpink"
13
+ def gpl(line)
14
+ if line.chomp.match( /^\s*(?<r>\d{1,3})\s+(?<g>\d{1,3})\s+(?<b>\d{1,3})(\s+(?<name>.*))?/ )
15
+ color = RGB.rgb $~[:r].to_i, $~[:g].to_i, $~[:b].to_i
16
+ color.name = $~[:name] if $~[:name]
17
+ color
18
+ else
19
+ nil
20
+ end
21
+ end
22
+
23
+ # Loads a gpl (Gimp color palette) source and returns an array of RGB objects.
24
+ #
25
+ # Options:
26
+ # - file: Path to a .gpl file to be loaded.
27
+ # - url: URL for a .gpl source to be loaded.
28
+ # - compact: Defaults to true. If set to false, returns nil for each line that can not be parsed to an RGB color.
29
+ # - freeze: Defaults to false. If set to true, returns a frozen array of frozen objects.
30
+ #
31
+ # @example String
32
+ # RGB.load_gpl "255 0 0\tred\n255 153 204\tpink\n"
33
+ # @example File
34
+ # RGB.load_gpl file: '/path/to/palette.gpl'
35
+ # RGB.load_gpl file: '/path/to/palette.gpl', compact: false
36
+ # @example URL
37
+ # RGB.load_gpl url: 'https://lospec.com/palette-list/yuko-tomita-time.gpl'
38
+ def load_gpl(source=nil, file: nil, url: nil, compact: true, freeze: false)
39
+
40
+ if ! source
41
+ if file
42
+ source = File.open file
43
+ elsif url
44
+ require 'open-uri'
45
+ source = URI.open url
46
+ end
47
+ end
48
+
49
+ if source.respond_to? :each_line
50
+ list = source.each_line.map { |line| RGB.gpl(line) }
51
+
52
+ if compact
53
+ list.compact!
54
+ end
55
+
56
+ if freeze
57
+ list.freeze
58
+ list.each &:freeze
59
+ end
60
+
61
+ list
62
+ else
63
+ raise ArgumentError, 'Not a valid source'
64
+ end
65
+ end
10
66
 
67
+ # Returns a header for a .gpl file (Gimp color palette). Includes an optional name and number of columns.
68
+ #
69
+ # @example
70
+ # RGB.gpl_header('Spring')
71
+ #
11
72
  # Reverse-engineered from:
12
73
  # - https://github.com/GNOME/gimp/blob/5d79fba8238a27b8691556489898d33b3fa0dda0/app/core/gimppalette-load.c
13
- def gpl_header(name, columns=nil)
74
+ def gpl_header(name=nil, columns: nil)
14
75
  "GIMP Palette\n" +
15
- "Name: #{name}\n" +
76
+ ( name ? "Name: #{name}\n" : '' ) +
16
77
  ( columns ? "Columns: #{columns}\n" : '' )
17
78
  end
18
79
 
19
80
  end
20
81
 
21
- ########################################################################
22
- # Instance methods #
23
- ########################################################################
82
+ #----------------------------------------------------------------------#
83
+ # Instance Methods #
84
+ #----------------------------------------------------------------------#
24
85
 
25
- # Returns the color in the format used in .gpl files (Gimp color palettes). A name for the color is optional.
26
- def gpl(name=nil)
27
- ( "%3d %3d %3d" % rgb ) + ( name ? "\t#{name}" : '' )
86
+ # Returns the color in the format used in .gpl files (Gimp color palettes), including its name (if present).
87
+ #
88
+ # You can optionally supply a name as argument.
89
+ def gpl(gpl_name=name)
90
+ ( "%3d %3d %3d" % rgb ) +
91
+ ( gpl_name.to_s.size != 0 ? "\t#{gpl_name}" : '' )
28
92
  end
29
93
 
30
94
  end
@@ -2,9 +2,9 @@ require 'redgreenblue/hsv'
2
2
 
3
3
  class RGB
4
4
 
5
- ########################################################################
6
- # Class methods #
7
- ########################################################################
5
+ #----------------------------------------------------------------------#
6
+ # Class Methods #
7
+ #----------------------------------------------------------------------#
8
8
 
9
9
  class << self
10
10
 
@@ -13,9 +13,9 @@ class RGB
13
13
 
14
14
  end
15
15
 
16
- ########################################################################
17
- # Instance methods #
18
- ########################################################################
16
+ #----------------------------------------------------------------------#
17
+ # Instance Methods #
18
+ #----------------------------------------------------------------------#
19
19
 
20
20
  # Returns color as HSB:
21
21
  # hue (0..360), saturation (0..1), brightness (0..1).
@@ -3,9 +3,9 @@ require 'redgreenblue/math'
3
3
 
4
4
  class RGB
5
5
 
6
- ########################################################################
7
- # Class methods #
8
- ########################################################################
6
+ #----------------------------------------------------------------------#
7
+ # Class Methods #
8
+ #----------------------------------------------------------------------#
9
9
 
10
10
  class << self
11
11
 
@@ -23,9 +23,9 @@ class RGB
23
23
 
24
24
  end
25
25
 
26
- ########################################################################
27
- # Instance methods #
28
- ########################################################################
26
+ #----------------------------------------------------------------------#
27
+ # Instance Methods #
28
+ #----------------------------------------------------------------------#
29
29
 
30
30
  # Returns color as HSL:
31
31
  # hue (0..360), saturation (0..1), lightness (0..1).
@@ -3,9 +3,9 @@ require 'redgreenblue/math'
3
3
 
4
4
  class RGB
5
5
 
6
- ########################################################################
7
- # Class methods #
8
- ########################################################################
6
+ #----------------------------------------------------------------------#
7
+ # Class Methods #
8
+ #----------------------------------------------------------------------#
9
9
 
10
10
  class << self
11
11
 
@@ -23,9 +23,9 @@ class RGB
23
23
 
24
24
  end
25
25
 
26
- ########################################################################
27
- # Instance methods #
28
- ########################################################################
26
+ #----------------------------------------------------------------------#
27
+ # Instance Methods #
28
+ #----------------------------------------------------------------------#
29
29
 
30
30
  # Returns color as HSV:
31
31
  # hue (0..360), saturation (0..1), value (0..1).
@@ -1,8 +1,8 @@
1
1
  class RGB
2
2
 
3
- ########################################################################
4
- # Class methods #
5
- ########################################################################
3
+ #----------------------------------------------------------------------#
4
+ # Class Methods #
5
+ #----------------------------------------------------------------------#
6
6
 
7
7
  class << self
8
8
 
@@ -48,9 +48,9 @@ class RGB
48
48
 
49
49
  end
50
50
 
51
- ########################################################################
52
- # Instance methods #
53
- ########################################################################
51
+ #----------------------------------------------------------------------#
52
+ # Instance Methods #
53
+ #----------------------------------------------------------------------#
54
54
 
55
55
  private
56
56
 
@@ -0,0 +1,14 @@
1
+ class RGB
2
+
3
+ # Returns the color's hue (0..360), whiteness (0..1), and blackness (0..1), as defined by the HWB color model.
4
+ #
5
+ # For achromatic colors, hue is nil.
6
+ #
7
+ # Based on:
8
+ # - http://alvyray.com/Papers/CG/HWB_JGTv208.pdf (PDF)
9
+ # - https://en.wikipedia.org/wiki/HWB_color_model
10
+ def hwb
11
+ [ hsv_h, cwk[1,2] ].flatten
12
+ end
13
+
14
+ end
@@ -3,11 +3,11 @@ class RGB
3
3
  private
4
4
 
5
5
  def _inspect_default(prefix='RGB')
6
- "#{prefix} ##{hex} (red=%1.5f green=%1.5f blue=%1.5f)" % [red, green, blue]
6
+ "#{prefix} #{_inspect_hex} (red=%1.5f green=%1.5f blue=%1.5f)" % [red, green, blue] + ( name ? ' ' + name : '' )
7
7
  end
8
8
 
9
9
  def _inspect_hex
10
- "##{hex}"
10
+ (self == snap ? '#' : '~') + hex
11
11
  end
12
12
 
13
13
  def _inspect_swatch
@@ -15,13 +15,17 @@ class RGB
15
15
  end
16
16
 
17
17
  def _inspect_short
18
- _inspect_swatch + " ##{hex}"
18
+ "#{_inspect_swatch} #{_inspect_hex}"
19
19
  end
20
20
 
21
21
  def _inspect_simple
22
22
  _inspect_default _inspect_swatch
23
23
  end
24
24
 
25
+ def _inspect_name
26
+ _inspect_swatch + ( name ? ' ' + name : '' )
27
+ end
28
+
25
29
  public
26
30
 
27
31
  # Returns a programmer-friendly representation of the object.
@@ -1,53 +1,73 @@
1
1
  class RGB
2
2
 
3
- # Creates a white RGB object.
4
- def self.white
5
- new(1,1,1)
6
- end
3
+ #----------------------------------------------------------------------#
4
+ # Class Methods #
5
+ #----------------------------------------------------------------------#
7
6
 
8
- # Creates a black RGB object.
9
- def self.black
10
- new(0,0,0)
11
- end
7
+ class << self
12
8
 
13
- # Creates a grey RGB object. Defaults to lightness 0.5, a middle grey. Black equals grey(0), white equals grey(1).
14
- #
15
- # ::gray is an alias for ::grey.
16
- def self.grey(lightness=0.5)
17
- new(lightness, lightness, lightness)
18
- end
9
+ # Creates a white RGB object.
10
+ def white
11
+ new(1,1,1)
12
+ end
19
13
 
20
- # Alias gray for grey.
21
- self.singleton_class.send(:alias_method, :gray, :grey)
14
+ # Creates a black RGB object.
15
+ def black
16
+ new(0,0,0)
17
+ end
22
18
 
23
- # Creates a pure red RGB object.
24
- def self.red
25
- new(1,0,0)
26
- end
19
+ # Creates a grey RGB object. Defaults to lightness 0.5, a middle grey. Black equals grey(0), white equals grey(1).
20
+ #
21
+ # ::gray is an alias for ::grey.
22
+ def grey(lightness=0.5)
23
+ new(lightness, lightness, lightness)
24
+ end
27
25
 
28
- # Creates a pure green RGB object.
29
- def self.green
30
- new(0,1,0)
31
- end
26
+ # Alias gray for grey.
27
+ alias gray grey
32
28
 
33
- # Creates a pure blue RGB object.
34
- def self.blue
35
- new(0,0,1)
36
- end
29
+ # Creates a pure red RGB object.
30
+ def red
31
+ new(1,0,0)
32
+ end
37
33
 
38
- # Creates a yellow RGB object.
39
- def self.yellow
40
- new(1,1,0)
41
- end
34
+ # Creates a pure green RGB object.
35
+ def green
36
+ new(0,1,0)
37
+ end
42
38
 
43
- # Creates a cyan RGB object.
44
- def self.cyan
45
- new(0,1,1)
46
- end
39
+ # Creates a pure blue RGB object.
40
+ def blue
41
+ new(0,0,1)
42
+ end
43
+
44
+ # Creates a yellow RGB object.
45
+ def yellow
46
+ new(1,1,0)
47
+ end
48
+
49
+ # Creates a cyan RGB object.
50
+ def cyan
51
+ new(0,1,1)
52
+ end
53
+
54
+ # Creates a magenta RGB object.
55
+ def magenta
56
+ new(1,0,1)
57
+ end
58
+
59
+ # Returns the 8 corners of the RGB cube.
60
+ def corners
61
+ [ black, red, yellow, green, cyan, blue, magenta, white ]
62
+ end
63
+
64
+ # Returns the centre of the RGB cube.
65
+ def centre
66
+ grey
67
+ end
68
+
69
+ alias center centre
47
70
 
48
- # Creates a magenta RGB object.
49
- def self.magenta
50
- new(1,0,1)
51
71
  end
52
72
 
53
73
  end
@@ -0,0 +1,8 @@
1
+ class RGB
2
+
3
+ # Returns the color in the format used by AppleScript (a 48-bit RGB triplet).
4
+ def applescript
5
+ "{%i, %i, %i}" % rrggbb
6
+ end
7
+
8
+ end
@@ -0,0 +1,49 @@
1
+ class RGB
2
+
3
+ # Matches this color to a set of colors by calculating their euclidean distance.
4
+ #
5
+ # Returns the given set of colors with their distance from this color, sorted by distance (nearest color first).
6
+ # @example What is nearer: red, grey or white?
7
+ # RGB.hex('f9c').match_distance [RGB.red, RGB.grey, RGB.white]
8
+ def match_distance(others)
9
+ others.map { |c| [ c, distance(c) ] }.sort_by { |a| a[1] }
10
+ end
11
+
12
+ # Matches this color to a set of colors using the CIE 1976 delta E formula.
13
+ #
14
+ # Returns the given set of colors with their difference from this color, sorted by difference (nearest color first).
15
+ # @example Find the 3 nearest CSS named colors
16
+ # RGB.hex('f9c').match_de76(RGB.css).first(3)
17
+ def match_de76(others)
18
+ others.map { |c| [ c, de76(c) ] }.sort_by { |a| a[1] }
19
+ end
20
+
21
+ # Matches this (reference) color to a set of colors using the CIE 1994 delta E formula.
22
+ #
23
+ # Returns the given set of colors with their difference from this color, sorted by difference (nearest color first).
24
+ #
25
+ # By default uses parameters for use in graphic arts, and reference conditions.
26
+ # Parameters (k1, k2, kl, kc, kh) can be individually overriden for different applications and for variations in conditions.
27
+ def match_de94(others, k1: 0.045, k2: 0.015, kl: 1, kc: 1, kh: 1)
28
+ others.map { |c| [ c, de94(c, k1: k1, k2: k2, kl: kl, kc: kc, kh: kh) ] }.sort_by { |a| a[1] }
29
+ end
30
+
31
+ # Matches this (reference) color to a set of colors using the CIE 1994 delta E formula.
32
+ #
33
+ # For use in graphic arts, under reference conditions.
34
+ #
35
+ # Returns the given set of colors with their difference from this color, sorted by difference (nearest color first).
36
+ def match_de94g(others)
37
+ others.map { |c| [ c, de94g(c) ] }.sort_by { |a| a[1] }
38
+ end
39
+
40
+ # Matches this (reference) color to a set of colors using the CIE 1994 delta E formula.
41
+ #
42
+ # For use with textiles, under reference conditions.
43
+ #
44
+ # Returns the given set of colors with their difference from this color, sorted by difference (nearest color first).
45
+ def match_de94t(others)
46
+ others.map { |c| [ c, de94t(c) ] }.sort_by { |a| a[1] }
47
+ end
48
+
49
+ end
@@ -36,4 +36,17 @@ class RGB
36
36
  RGB.new(v[0].red, v[1].green, v[2].blue)
37
37
  end
38
38
 
39
+ # Returns the euclidean distance between this color and another color.
40
+ #
41
+ # When you imagine a color as a point in a 3-dimensional space,
42
+ # the dimensions being red, green, and blue,
43
+ # this is the distance between two colors.
44
+ def distance(another)
45
+ (
46
+ ( (another.red - red ) ** 2) +
47
+ ( (another.green - green) ** 2) +
48
+ ( (another.blue - blue ) ** 2)
49
+ ) ** (1/2.0)
50
+ end
51
+
39
52
  end
@@ -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
@@ -22,6 +22,8 @@ class RGB
22
22
  # @example Use
23
23
  # RGB.magenta.to_philips_hue_api_hsb_arguments
24
24
  # => {"on"=>true, "bri"=>254, "hue"=>54613, "sat"=>254}
25
+ # RGB.black.to_philips_hue_api_hsb_arguments
26
+ # => {"on"=>false}
25
27
  # @return [Hash] API arguments
26
28
  def to_philips_hue_api_hsb_arguments(black_off=true)
27
29
  my_hsb = hsb
@@ -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
@@ -32,12 +32,12 @@ class RGB
32
32
  # Based on:
33
33
  # - Color for the Sciences, pp. 575–591
34
34
  # - https://lirias.kuleuven.be/retrieve/306124 (PDF)
35
- def ostwald_cwk
35
+ def ostwald_cwk(round: true)
36
36
  [
37
37
  color_portion = values.max - values.min,
38
38
  white_portion = values.min,
39
39
  1 - color_portion - white_portion
40
- ]
40
+ ].map { |v| round ? v.round(8) : v }
41
41
  end
42
42
 
43
43
  alias cwk ostwald_cwk
@@ -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
@@ -1,7 +1,7 @@
1
1
  class RGB
2
2
 
3
3
  # redgreenblue version.
4
- VERSION = '0.11.0'
4
+ VERSION = '0.15.0'
5
5
 
6
6
  # Returns RGB::VERSION.
7
7
  def self.version
@@ -0,0 +1,40 @@
1
+ class RGB
2
+
3
+ # Prints a color swatch and details for the RGB object, using multiple lines.
4
+ #
5
+ # You can optionally supply a second color to be shown inside the swatch, for comparison.
6
+ def view(other=nil)
7
+ puts _inspect_view other
8
+ end
9
+
10
+ alias v view
11
+
12
+ private
13
+
14
+ def _inspect_view(other=nil)
15
+ o = []
16
+ o << 3.times.map { terminal_background + " \e[0m "}
17
+ o << [ "#{_inspect_hex} ", '%-7.7s ' % color_space, ' ' ]
18
+
19
+ if other
20
+ o[0][1] = terminal_background + ' ' + other.terminal_background + ' ' + terminal_background + " \e[0m "
21
+ end
22
+
23
+ o << components.map { |c| c.terminal_background + " \e[0m " }
24
+ o << %w(R: G: B:)
25
+ o << values.map { |v| '%1.5f ' % v }
26
+ o << rgb.map { |v| '%3d ' % v }
27
+
28
+ o << %w(H: S: L:)
29
+ o << hsl.map { |v| v ? ('%7.3f ' % v) : ' - ' }
30
+ o << %w(H: S: B:)
31
+ o << hsb.map { |v| v ? ('%7.3f ' % v) : ' - ' }
32
+
33
+ o << 3.times.map { (ostwald_color ? ostwald_color.terminal_background + " \e[0m " : ' ') }
34
+ o << %w(C: W: K:)
35
+ o << ostwald_cwk.map { |v| '%1.3f ' % v }
36
+
37
+ o.transpose.map(&:join).join("\n")
38
+ end
39
+
40
+ 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,53 @@ 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
+
109
+ # Returns true if this is one of the 216 so-called "web safe" colors, otherwise false.
110
+ def web_safe?
111
+ ( values - [0.0, 0.2, 0.4, 0.6, 0.8, 1.0] ).empty?
112
+ end
113
+
10
114
  end
data/lib/redgreenblue.rb CHANGED
@@ -11,15 +11,19 @@ end
11
11
 
12
12
  hsl hsv hsb
13
13
 
14
- ostwald
14
+ ostwald hwb
15
15
 
16
- gamma cie
16
+ gamma
17
17
 
18
- inspect lazy
18
+ cie_1931 cie_1976 cie_1994
19
19
 
20
- rgb565 bgr24bit gif terminal web gpl
20
+ name
21
21
 
22
- mix misc random
22
+ inspect view lazy
23
+
24
+ rgb565 bgr24bit gif terminal web gpl mac
25
+
26
+ match mix misc random
23
27
 
24
28
  os
25
29
 
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redgreenblue
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.0
4
+ version: 0.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - lllist.eu
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-23 00:00:00.000000000 Z
11
+ date: 2021-11-10 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description:
14
- email:
13
+ description:
14
+ email:
15
15
  executables: []
16
16
  extensions: []
17
17
  extra_rdoc_files: []
@@ -21,7 +21,9 @@ 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
+ - lib/redgreenblue/cie_1931.rb
25
+ - lib/redgreenblue/cie_1976.rb
26
+ - lib/redgreenblue/cie_1994.rb
25
27
  - lib/redgreenblue/gamma.rb
26
28
  - lib/redgreenblue/gif.rb
27
29
  - lib/redgreenblue/gpl.rb
@@ -30,20 +32,26 @@ files:
30
32
  - lib/redgreenblue/hsl.rb
31
33
  - lib/redgreenblue/hsv.rb
32
34
  - lib/redgreenblue/hsx_shared.rb
35
+ - lib/redgreenblue/hwb.rb
33
36
  - lib/redgreenblue/inspect.rb
34
37
  - lib/redgreenblue/int.rb
35
38
  - lib/redgreenblue/lazy.rb
39
+ - lib/redgreenblue/mac.rb
40
+ - lib/redgreenblue/match.rb
36
41
  - lib/redgreenblue/math.rb
37
42
  - lib/redgreenblue/misc.rb
38
43
  - lib/redgreenblue/mix.rb
44
+ - lib/redgreenblue/name.rb
39
45
  - lib/redgreenblue/opt/philipshue.rb
40
46
  - lib/redgreenblue/os.rb
41
47
  - lib/redgreenblue/os/mac.rb
42
48
  - lib/redgreenblue/ostwald.rb
49
+ - lib/redgreenblue/palettes/css.gpl
43
50
  - lib/redgreenblue/random.rb
44
51
  - lib/redgreenblue/rgb565.rb
45
52
  - lib/redgreenblue/terminal.rb
46
53
  - lib/redgreenblue/version.rb
54
+ - lib/redgreenblue/view.rb
47
55
  - lib/redgreenblue/web.rb
48
56
  homepage: https://github.com/lllisteu/redgreenblue
49
57
  licenses:
@@ -52,7 +60,7 @@ metadata:
52
60
  homepage_uri: https://github.com/lllisteu/redgreenblue
53
61
  changelog_uri: https://github.com/lllisteu/redgreenblue/blob/master/History.md
54
62
  documentation_uri: https://www.rubydoc.info/gems/redgreenblue/RGB
55
- post_install_message:
63
+ post_install_message:
56
64
  rdoc_options: []
57
65
  require_paths:
58
66
  - lib
@@ -67,8 +75,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
67
75
  - !ruby/object:Gem::Version
68
76
  version: '0'
69
77
  requirements: []
70
- rubygems_version: 3.1.2
71
- signing_key:
78
+ rubygems_version: 3.2.22
79
+ signing_key:
72
80
  specification_version: 4
73
81
  summary: A simple Ruby library for handling RGB colors.
74
82
  test_files: []