redgreenblue 0.11.0 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
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: []