colorspace 0.1.0 → 0.1.2

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: c139dfc8f81959c4676b6626d5e72bcca448b829213a624f9bced835e662ce3e
4
- data.tar.gz: 7eadea0f02c8d3b44c6c11c7bca30b66cb1ce2e5f8630c81c9ab3bea7af58d56
3
+ metadata.gz: 9400e62857f08e86defabffe2f88ae73dc05ac5f05cc29f575a86917a2121c45
4
+ data.tar.gz: 8e38f06fc5d6d804a2cb81bcc3dbc0e2176987f9c7890088d62809998b1bcc73
5
5
  SHA512:
6
- metadata.gz: 867d76ec2efb1ca07ec2d8da0308fdeea8f1e2437277e6cb6d9b3a3d839b003abb1b3020bc0b81160625b536e856c717f15f2dd8ce5361fe49959cc025b546c3
7
- data.tar.gz: 78ea353372d5c30ae12c5e3c0c61744b9a587b0d4db1f3c733b10cb0f3e106079ba753eed6aae3d70b11f86ad595027f4fc76733c8a881f7d3bca13df5f3cda1
6
+ metadata.gz: 6abdcfa05487d616ad1972ac847bbc38744ceda59fd203b46327db3f3e7a7b162f8b2b201335c0d4f23dde49a05828f3fbbcf51d9358a82267b0ae20d2ad9969
7
+ data.tar.gz: e6e3d20acac710720d55f0e5d42fc9b7e32ee61c8eab857a24211ccd0e12224bbff7591d4a5a6d02c628d82dd56e73fce3cb0f5bb8a04ee9a9307dc5d41edfc7
data/.rubocop.yml CHANGED
@@ -38,3 +38,6 @@ Style/DataInheritance:
38
38
 
39
39
  Style/ParallelAssignment:
40
40
  Enabled: false
41
+
42
+ Gemspec/RequireMFA:
43
+ Enabled: false
data/Gemfile.lock CHANGED
@@ -1,7 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- colorspace (0.1.0)
4
+ colorspace (0.1.1)
5
+ matrix (~> 0.4)
5
6
 
6
7
  GEM
7
8
  remote: https://rubygems.org/
@@ -9,6 +10,7 @@ GEM
9
10
  ast (2.4.2)
10
11
  json (2.7.1)
11
12
  language_server-protocol (3.17.0.3)
13
+ matrix (0.4.2)
12
14
  minitest (5.20.0)
13
15
  parallel (1.24.0)
14
16
  parser (3.2.2.4)
data/colorspace.gemspec CHANGED
@@ -33,7 +33,6 @@ Gem::Specification.new do |spec|
33
33
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
34
34
  spec.require_paths = ['lib']
35
35
 
36
- # Uncomment to register a new dependency of your gem
37
- # spec.add_dependency "example-gem", "~> 1.0"
36
+ spec.add_dependency 'matrix', '~> 0.4'
38
37
  # spec.metadata['rubygems_mfa_required'] = 'true'
39
38
  end
@@ -0,0 +1,175 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'matrix'
4
+
5
+ # Library for working with RGB, XYZ, and LAB colorspaces
6
+ module Colorspace
7
+ # rubocop: disable Layout/SpaceInsideArrayLiteralBrackets
8
+ # rubocop: disable Layout/ExtraSpacing
9
+ RGB_XYZ_MATRIX = Matrix[
10
+ [ 0.4124564, 0.3575761, 0.1804375 ],
11
+ [ 0.2126729, 0.7151522, 0.0721750 ],
12
+ [ 0.0193339, 0.1191920, 0.9503041 ]
13
+ ].freeze
14
+
15
+ XYZ_RGB_MATRIX = Matrix[
16
+ [ 3.2404542, -1.5371385, -0.4985314 ],
17
+ [ -0.9692660, 1.8760108, 0.0415560 ],
18
+ [ 0.0556434, -0.2040259, 1.0572252 ]
19
+ ].freeze
20
+ # rubocop: enable Layout/ExtraSpacing
21
+ # rubocop: enable Layout/SpaceInsideArrayLiteralBrackets
22
+
23
+ ##
24
+ # A tristimulus value in the CIE 1931 space.
25
+ class XYZTristimulus < Data.define(:x, :y, :z)
26
+ # @dynamic x, y, z, initialize
27
+
28
+ def to_srgb_linear
29
+ r, g, b = (XYZ_RGB_MATRIX * Matrix[[x], [y], [z]]).to_a.flatten
30
+
31
+ SRGBLinearColor.new(r:, g:, b:)
32
+ end
33
+
34
+ def to_srgb
35
+ to_srgb_linear.gamma_compress
36
+ end
37
+
38
+ private def scale_f(val)
39
+ delta = 6.0 / 29
40
+ t = val
41
+
42
+ if t > delta**3
43
+ t**(1.0 / 3)
44
+ else
45
+ (t / (3 * (delta**2))) + (4.0 / 29)
46
+ end
47
+ end
48
+
49
+ # rubocop: disable Metrics/AbcSize
50
+ def to_cielab(illuminant: D65)
51
+ x_, y_, z_ = x * 100, y * 100, z * 100
52
+ xn, yn, zn = illuminant.x, illuminant.y, illuminant.z
53
+
54
+ l = (116 * scale_f(y_ / yn)) - 16
55
+ a = 500 * (scale_f(x_ / xn) - scale_f(y_ / yn))
56
+ b = 200 * (scale_f(y_ / yn) - scale_f(z_ / zn))
57
+
58
+ CIELABColor.new(l:, a:, b:)
59
+ end
60
+ # rubocop: enable Metrics/AbcSize
61
+
62
+ def to_ary = [x, y, z]
63
+ def to_a = to_ary
64
+ end
65
+
66
+ D65 = XYZTristimulus.new(x: 95.047, y: 100.0, z: 108.883)
67
+ D50 = XYZTristimulus.new(x: 96.42, y: 100.0, z: 82.51)
68
+
69
+ ##
70
+ # An RGB value in the sRGB colorspace.
71
+ class SRGBColor < Data.define(:r, :g, :b)
72
+ # @dynamic r, g, b, initialize
73
+ def self.from_hex(hex)
74
+ r, g, b = hex.chars.last(6).each_slice(2)
75
+ .map { |c| c.join.to_i(16) / 255.0 }
76
+
77
+ new(r: r || 0.0, g: g || 0.0, b: b || 0.0)
78
+ end
79
+
80
+ def to_hex
81
+ [r, g, b].map { |val|
82
+ (val * 255).round.clamp(0, 255).to_s(16).rjust(2, '0')
83
+ }.join
84
+ end
85
+
86
+ private def gamma_expand_one(val)
87
+ if val <= 0.04045
88
+ val / 12.92
89
+ else
90
+ ((val + 0.055) / 1.055)**2.4
91
+ end
92
+ end
93
+
94
+ def to_xyz
95
+ gamma_expand.to_xyz
96
+ end
97
+
98
+ def gamma_expand
99
+ SRGBLinearColor.new(
100
+ r: gamma_expand_one(r),
101
+ g: gamma_expand_one(g),
102
+ b: gamma_expand_one(b)
103
+ )
104
+ end
105
+
106
+ def to_ary = [r, g, b]
107
+ def to_a = to_ary
108
+ end
109
+
110
+ ##
111
+ # A gamma-expanded ("linear light") RGB value in the sRGB colorspace.
112
+ class SRGBLinearColor < Data.define(:r, :g, :b)
113
+ def to_xyz
114
+ x, y, z = (RGB_XYZ_MATRIX * Matrix[[r], [g], [b]]).to_a.flatten
115
+ XYZTristimulus.new(x:, y:, z:)
116
+ end
117
+
118
+ private def gamma_compress_one(val)
119
+ if val <= 0.0031308
120
+ 12.92 * val
121
+ else
122
+ (1.055 * (val**(1.0 / 2.4))) - 0.055
123
+ end
124
+ end
125
+
126
+ def gamma_compress
127
+ SRGBColor.new(
128
+ r: gamma_compress_one(r),
129
+ g: gamma_compress_one(g),
130
+ b: gamma_compress_one(b)
131
+ )
132
+ end
133
+
134
+ def to_ary = [r, g, b]
135
+ def to_a = to_ary
136
+ end
137
+
138
+ ##
139
+ # A color in the CIE LAB color space.
140
+ class CIELABColor < Data.define(:l, :a, :b)
141
+ def self.from_hex(...)
142
+ SRGBColor.from_hex(...).to_xyz.to_cielab
143
+ end
144
+
145
+ def to_hex
146
+ to_xyz.to_srgb.to_hex
147
+ end
148
+
149
+ # rubocop: disable Metrics/AbcSize
150
+ def to_xyz(illuminant: D65)
151
+ xn, yn, zn = illuminant.x, illuminant.y, illuminant.z
152
+
153
+ p = (l + 16) / 116.0
154
+
155
+ x = xn * ((p + (a / 500.0))**3) / 100.0
156
+ y = yn * (p**3) / 100.0
157
+ z = zn * ((p - (b / 200.0))**3) / 100.0
158
+
159
+ XYZTristimulus.new(x:, y:, z:)
160
+ end
161
+ # rubocop: enable Metrics/AbcSize
162
+
163
+ def cie76(other)
164
+ (((other.l - l)**2) + ((other.a - a)**2) + ((other.b - b)**2))**0.5
165
+ end
166
+
167
+ def ciede2000(other)
168
+ # TODO: write this
169
+ cie76(other)
170
+ end
171
+
172
+ def to_ary = [l, a, b]
173
+ def to_a = to_ary
174
+ end
175
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Colorspace
4
- VERSION = '0.1.0'
4
+ VERSION = '0.1.2'
5
5
  end
data/lib/colorspace.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'colorspace/version'
4
+ require_relative 'colorspace/colorlib'
4
5
 
5
6
  module Colorspace
6
7
  class Error < StandardError; end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: colorspace
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anna Kudriavtsev
@@ -9,7 +9,21 @@ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
11
  date: 1980-01-01 00:00:00.000000000 Z
12
- dependencies: []
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: matrix
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.4'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.4'
13
27
  description:
14
28
  email:
15
29
  - anna328p@gmail.com
@@ -29,6 +43,7 @@ files:
29
43
  - flake.lock
30
44
  - flake.nix
31
45
  - lib/colorspace.rb
46
+ - lib/colorspace/colorlib.rb
32
47
  - lib/colorspace/version.rb
33
48
  - shell.nix
34
49
  - sig/colorspace.rbs