redgreenblue 0.9.0 → 0.14.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: 3acd4edad3c6c358886e6c49138133f207571b610d8ea980fd6ff4d0cb38b7a8
4
- data.tar.gz: 81833b3ed57dfcde3c0558f196e7be284ac040e56330019a994e214b39c75463
3
+ metadata.gz: a61701a3122fc8e8b4f4352142862f7e3d63ed317cea1321cfe1bafd5d697a42
4
+ data.tar.gz: 4a76d444f8080acb74656963654375e975eb91eb0068f6c4012e9233daf58bb7
5
5
  SHA512:
6
- metadata.gz: 57a8b63684a52f0495ee14c47a391a42bce9ce40914b9eee7523d1685fc4a66135ccb453b9c5c2ab68900dc700266e71651cb420fd0cd3cbdcf57cecb3012d27
7
- data.tar.gz: 78917822fe1a7cd67acc98912adf1107736609fd996300003bc7c77ff02cbfcdabf6efce4b86481f27dbb568612237dbee726563de76dab1b60188b9c27e2ef8
6
+ metadata.gz: 502bc188625f8df6fc3a55fa53454728602843ddd39f61c8199009f0e55c1fbd38a496d27c889c565b578ae85dd9cd051a457deec87979374d89006833f37707
7
+ data.tar.gz: b811b0e1bc0bd366406be48eead2f11328c8304eee6eb34192bc92c40c31a4683dc5771a3944650749707df7e5a40e330d64c02b7f7818c0064dca5253ffe019
data/lib/redgreenblue.rb CHANGED
@@ -1,30 +1,30 @@
1
1
  class RGB
2
2
  end
3
3
 
4
- require 'redgreenblue/version'
4
+ %w(
5
5
 
6
- require 'redgreenblue/base'
6
+ version
7
7
 
8
- require 'redgreenblue/24bit'
9
- require 'redgreenblue/48bit'
10
- require 'redgreenblue/hex'
11
- require 'redgreenblue/int'
8
+ base
12
9
 
13
- require 'redgreenblue/gamma'
14
- require 'redgreenblue/hsl_hsv'
15
- require 'redgreenblue/cie'
10
+ 24bit 48bit hex int
16
11
 
17
- require 'redgreenblue/inspect'
18
- require 'redgreenblue/lazy'
12
+ hsl hsv hsb
19
13
 
20
- require 'redgreenblue/rgb565'
21
- require 'redgreenblue/bgr24bit'
22
- require 'redgreenblue/gif'
23
- require 'redgreenblue/terminal'
24
- require 'redgreenblue/web'
14
+ ostwald hwb
25
15
 
26
- require 'redgreenblue/mix'
27
- require 'redgreenblue/misc'
28
- require 'redgreenblue/random'
16
+ gamma
29
17
 
30
- require 'redgreenblue/os'
18
+ cie_1931 cie_1976
19
+
20
+ name
21
+
22
+ inspect view lazy
23
+
24
+ rgb565 bgr24bit gif terminal web gpl mac
25
+
26
+ match mix misc random
27
+
28
+ os
29
+
30
+ ).each { |m| require "redgreenblue/#{m}" }
@@ -51,6 +51,17 @@ class RGB
51
51
  c
52
52
  end
53
53
 
54
+ # Sets the red, green, and blue values to those of the nearest 24-bit color.
55
+ def snap!
56
+ self.rgb = rgb
57
+ self
58
+ end
59
+
60
+ # Creates a new RGB object containing the nearest 24-bit color.
61
+ def snap
62
+ RGB.rgb rgb
63
+ end
64
+
54
65
  # Calls the given block for each 24-bit RGB color (from black to white), passing the color as an RGB object.
55
66
  #
56
67
  # Returns the number of iterations.
@@ -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,94 @@
1
+ class RGB
2
+
3
+ #----------------------------------------------------------------------#
4
+ # Class Methods #
5
+ #----------------------------------------------------------------------#
6
+
7
+ class << self
8
+
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
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
+ #
72
+ # Reverse-engineered from:
73
+ # - https://github.com/GNOME/gimp/blob/5d79fba8238a27b8691556489898d33b3fa0dda0/app/core/gimppalette-load.c
74
+ def gpl_header(name=nil, columns: nil)
75
+ "GIMP Palette\n" +
76
+ ( name ? "Name: #{name}\n" : '' ) +
77
+ ( columns ? "Columns: #{columns}\n" : '' )
78
+ end
79
+
80
+ end
81
+
82
+ #----------------------------------------------------------------------#
83
+ # Instance Methods #
84
+ #----------------------------------------------------------------------#
85
+
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}" : '' )
92
+ end
93
+
94
+ end
@@ -0,0 +1,61 @@
1
+ require 'redgreenblue/hsv'
2
+
3
+ class RGB
4
+
5
+ #----------------------------------------------------------------------#
6
+ # Class Methods #
7
+ #----------------------------------------------------------------------#
8
+
9
+ class << self
10
+
11
+ # Creates a new RGB object from HSB values: hue (0..360), saturation (0..1), and brightness (0..1).
12
+ alias hsb hsv
13
+
14
+ end
15
+
16
+ #----------------------------------------------------------------------#
17
+ # Instance Methods #
18
+ #----------------------------------------------------------------------#
19
+
20
+ # Returns color as HSB:
21
+ # hue (0..360), saturation (0..1), brightness (0..1).
22
+ # When saturation is 0, hue is nil.
23
+ alias hsb hsv
24
+
25
+ # Returns the object's HSB-hue (0..360).
26
+ alias hsb_h hsv_h
27
+
28
+ # Returns the object's HSB-saturation (0..1).
29
+ alias hsb_s hsv_s
30
+
31
+ # Returns the object's HSB-brightness (0..1).
32
+ alias hsb_b hsv_v
33
+
34
+ # Sets red, green, and blue using HSB values: hue (0..360), saturation (0..1), and brightness (0..1).
35
+ alias hsb= hsv=
36
+
37
+ # Sets HSB-hue to a number of degrees (0..360) or nil.
38
+ #
39
+ # Adjusts red, green, and blue, leaving HSB-saturation and -brightness unchanged.
40
+ # When hue is nil, saturation will be 0.
41
+ alias hsb_h= hsv_h=
42
+
43
+ # Sets HSB-saturation to a number between 0 and 1.
44
+ #
45
+ # Adjusts red, green, and blue, leaving HSB-hue and -brightness unchanged.
46
+ # When saturation is 0, hue will be nil.
47
+ alias hsb_s= hsv_s=
48
+
49
+ # Sets HSB-brightness to a number between 0 and 1.
50
+ #
51
+ # Adjusts red, green, and blue, leaving HSB-hue and -saturation unchanged.
52
+ # When brightness is 0, hue will be nil, and saturation will be 0.
53
+ alias hsb_b= hsv_v=
54
+
55
+ # Sets red, green, and blue by rotating the object's HSB-hue a number of degrees.
56
+ alias hsb_rotate! hsv_rotate!
57
+
58
+ # Creates one or more new RGB objects by rotating this object's HSB-hue a number of degrees.
59
+ alias hsb_rotate hsv_rotate
60
+
61
+ end
@@ -0,0 +1,96 @@
1
+ require 'redgreenblue/hsx_shared'
2
+ require 'redgreenblue/math'
3
+
4
+ class RGB
5
+
6
+ #----------------------------------------------------------------------#
7
+ # Class Methods #
8
+ #----------------------------------------------------------------------#
9
+
10
+ class << self
11
+
12
+ # Creates a new RGB object from HSL values: hue (0..360), saturation (0..1), and lightness (0..1).
13
+ def hsl(*a)
14
+ new hsl_to_values(*a)
15
+ end
16
+
17
+ # Calculates RGB values from HSL.
18
+ # Given hue (0..360), saturation (0..1), and lightness (0..1),
19
+ # returns red, green, and blue as three values between 0 and 1.
20
+ def hsl_to_values(*a)
21
+ hsm_to_values(:hsl, a)
22
+ end
23
+
24
+ end
25
+
26
+ #----------------------------------------------------------------------#
27
+ # Instance Methods #
28
+ #----------------------------------------------------------------------#
29
+
30
+ # Returns color as HSL:
31
+ # hue (0..360), saturation (0..1), lightness (0..1).
32
+ # When saturation is 0, hue is nil.
33
+ def hsl
34
+ hsl_hsv_c[0]
35
+ end
36
+
37
+ # Returns the object's HSL-hue (0..360).
38
+ def hsl_h
39
+ hsl[0]
40
+ end
41
+
42
+ # Returns the object's HSL-saturation (0..1).
43
+ def hsl_s
44
+ hsl[1]
45
+ end
46
+
47
+ # Returns the object's HSL-lightness (0..1).
48
+ def hsl_l
49
+ hsl[2]
50
+ end
51
+
52
+ # Sets red, green, and blue using HSL values: hue (0..360), saturation (0..1), and lightness (0..1).
53
+ def hsl=(*a)
54
+ self.values = RGB.hsl_to_values(*a)
55
+ end
56
+
57
+ # Sets HSL-hue to a number of degrees (0..360) or nil.
58
+ #
59
+ # Adjusts red, green, and blue, leaving saturation and lightness unchanged.
60
+ # When hue is nil, saturation will be 0.
61
+ def hsl_h=(degrees)
62
+ self.hsl = hsl.fill(degrees,0,1)
63
+ end
64
+
65
+ # Sets HSL-saturation to a value between 0 and 1.
66
+ #
67
+ # Adjusts red, green, and blue, leaving hue and lightness unchanged.
68
+ # When saturation is 0, hue will be nil.
69
+ def hsl_s=(value)
70
+ self.hsl = hsl.fill(value ,1,1)
71
+ end
72
+
73
+ # Sets HSL-lightness to a value between 0 and 1.
74
+ #
75
+ # Adjusts red, green, and blue, leaving hue and saturation unchanged.
76
+ # When lightness is 0 or 1, hue will be nil, and saturation will be 0.
77
+ def hsl_l=(value)
78
+ self.hsl = hsl.fill(value ,2,1)
79
+ end
80
+
81
+ # Sets red, green, and blue by rotating the object's HSL-hue a number of degrees.
82
+ def hsl_rotate!(degrees)
83
+ self.hsl = zip_add(hsl, [degrees, 0, 0])
84
+ self
85
+ end
86
+
87
+ # Creates one or more new RGB objects by rotating this object's HSL-hue a number of degrees.
88
+ def hsl_rotate(a_degrees, *b_degrees)
89
+ if a_degrees.class != Array and b_degrees.none?
90
+ RGB.hsl zip_add(hsl, [a_degrees, 0, 0])
91
+ else
92
+ ( [a_degrees] + b_degrees ).flatten.map { |degrees| RGB.hsl zip_add(hsl, [degrees, 0, 0]) }
93
+ end
94
+ end
95
+
96
+ end