recolor 0.1.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0f36003993048fe3779cebfe5a674e7937e9d007
4
+ data.tar.gz: e9b3747ba265f90aa021973729071aa218c4e475
5
+ SHA512:
6
+ metadata.gz: de88f6cc4fa94eab41a2f2bf3cc1a0f746993a5a314a729cf4315efbef415fa309ee1ee150cd2cf168b2d3b38b73d7af4de4e5b599277588974baf1f7c8bba4e
7
+ data.tar.gz: 3a708f24e8a041cfd1d83aaa013106fe532bd1d234927e1d72fa48a0ba055294a70d33be56967c517966710d557bbc0a317ca35957d20d00c61ba03afb15cc86
@@ -0,0 +1,70 @@
1
+ require "recolor/version"
2
+
3
+ module Recolor
4
+ require "recolor/color"
5
+ require "recolor/models"
6
+ require "recolor/models/hex"
7
+ require "recolor/models/hsluv"
8
+ require "recolor/models/hpluv"
9
+ require "recolor/models/lch"
10
+ require "recolor/models/luv"
11
+ require "recolor/models/rgb"
12
+ require "recolor/models/xyz"
13
+ require "recolor/converter"
14
+
15
+ class Recolor
16
+ attr_accessor :converter
17
+ attr_accessor :models
18
+
19
+ def initialize
20
+ @models = {}
21
+ @models[:hex] = Models::Hex.new
22
+ @models[:hpluv] = Models::HPLuv.new
23
+ @models[:hsluv] = Models::HSLuv.new
24
+ @models[:lch] = Models::LCh.new
25
+ @models[:luv] = Models::Luv.new
26
+ @models[:rgb] = Models::RGB.new
27
+ @models[:xyz] = Models::XYZ.new
28
+ @converter = Converter.new
29
+ @converter.models[:hex] = @models[:hex]
30
+ @converter.models[:hpluv] = @models[:hpluv]
31
+ @converter.models[:hsluv] = @models[:hsluv]
32
+ @converter.models[:lch] = @models[:lch]
33
+ @converter.models[:luv] = @models[:luv]
34
+ @converter.models[:rgb] = @models[:rgb]
35
+ @converter.models[:xyz] = @models[:xyz]
36
+ end
37
+
38
+ def color(model, tuple)
39
+ @color = Color.new(model, tuple)
40
+
41
+ return self.clone
42
+ end
43
+
44
+ def to(model)
45
+ raise Exception.new("Color definition not found.") unless @color
46
+
47
+ source = @color.model
48
+ tuple = @color.tuple
49
+ tuple = @converter.convert(tuple, source, model)
50
+
51
+ return color(model, tuple)
52
+ end
53
+
54
+ def model
55
+ return @color.model
56
+ end
57
+
58
+ def tuple
59
+ return @color.tuple
60
+ end
61
+
62
+ def format
63
+ yield @color.tuple
64
+ end
65
+
66
+ def to_s
67
+ return @models[model].print(tuple)
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,11 @@
1
+ module Recolor
2
+ class Color
3
+ attr_accessor :model
4
+ attr_accessor :tuple
5
+
6
+ def initialize(model, tuple)
7
+ @model = model
8
+ @tuple = tuple
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,53 @@
1
+ module Recolor
2
+ class Converter
3
+ attr_accessor :models
4
+
5
+ def initialize
6
+ @models = {}
7
+ end
8
+
9
+ def convert(tuple, source, destination)
10
+ return tuple unless source != destination
11
+
12
+ raise ArgumentError.new("No #{source} model found.") unless @models.include?(source)
13
+
14
+ @steps = []
15
+ resolve(source, destination, @models)
16
+
17
+ raise ArgumentError.new("Unable to convert from #{source} to #{destination}.") if @steps.empty?
18
+
19
+ model = @models[source]
20
+
21
+ @steps.each do |step|
22
+ tuple = model.send(step, tuple)
23
+ model = @models[step]
24
+ end
25
+
26
+ return tuple
27
+ end
28
+
29
+ private
30
+
31
+ def resolve(source, destination, models)
32
+ model = models[source]
33
+ models = models.reject { |name| name == source }
34
+
35
+ models.keys.each do |name|
36
+ if model.respond_to?(destination)
37
+ @steps << destination
38
+ end
39
+
40
+ if @steps.include?(destination)
41
+ break
42
+ end
43
+
44
+ if model.respond_to?(name)
45
+ @steps << name
46
+ resolve(name, destination, models)
47
+ end
48
+ end
49
+
50
+ @steps = @steps.reject { |name| name == source } unless @steps.include?(destination)
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,20 @@
1
+ module Recolor
2
+ module Models
3
+ class Model
4
+ attr_accessor :format
5
+
6
+ KAPPA = 903.2962962962963
7
+ EPSILON = 0.0088564516790356308
8
+
9
+ def initialize
10
+ @format = lambda do |tuple|
11
+ return tuple
12
+ end
13
+ end
14
+
15
+ def print(tuple)
16
+ return "#{@format.call(tuple)}"
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,21 @@
1
+ module Recolor
2
+ module Models
3
+ class Hex < Model
4
+ def rgb(tuple)
5
+ hex = [
6
+ tuple[0],
7
+ tuple[1],
8
+ tuple[2]
9
+ ]
10
+
11
+ rgb = hex.map do |v|
12
+ v = v + v if v.length == 1
13
+ v = v.hex
14
+ v = v / 255
15
+ end
16
+
17
+ return rgb
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,33 @@
1
+ module Recolor
2
+ module Models
3
+ class HPLuv < Model
4
+ def lch(tuple)
5
+ h = tuple[0]
6
+ s = tuple[1]
7
+ l = tuple[2]
8
+
9
+ return [100, 0.0, h] if l > 99.9999999
10
+ return [0.0, 0.0, h] if l < 0.00000001
11
+
12
+ chroma = HPLuv.chroma(l)
13
+ c = chroma / 100.0 * s
14
+
15
+ return [l, c, h]
16
+ end
17
+
18
+ def HPLuv.chroma(l)
19
+ lengths = []
20
+
21
+ HSLuv.bounds(l).each do |line|
22
+ m = line[0]
23
+ b = line[1]
24
+ x = (b - 0.0) / ((-1.0 / m) - m)
25
+ length = Math.sqrt(x**2 + (b + x * m)**2)
26
+ lengths << length
27
+ end
28
+
29
+ return lengths.min
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,51 @@
1
+ module Recolor
2
+ module Models
3
+ class HSLuv < Model
4
+ def lch(tuple)
5
+ h = tuple[0]
6
+ s = tuple[1]
7
+ l = tuple[2]
8
+
9
+ return [100, 0.0, h] if l > 99.9999999
10
+ return [0.0, 0.0, h] if l < 0.00000001
11
+
12
+ chroma = HSLuv.chroma(l, h)
13
+ c = chroma / 100.0 * s
14
+
15
+ return [l, c, h]
16
+ end
17
+
18
+ def HSLuv.bounds(l)
19
+ s = ((l + 16)**3) / 1560896.0
20
+ s = s > EPSILON ? s : l / KAPPA
21
+ matrix = RGB::MATRIX.to_a
22
+ lines = []
23
+
24
+ matrix.each do |m1, m2, m3|
25
+ [0, 1].each do |d|
26
+ bottom = (632260 * m3 - 126452 * m2) * s + 126452 * d
27
+ m = ((284517 * m1 - 94839 * m3) * s) / bottom
28
+ b = ((838422 * m3 + 769860 * m2 + 731718 * m1) * l * s - 769860 * d * l) / bottom
29
+ lines << [m, b]
30
+ end
31
+ end
32
+
33
+ return lines
34
+ end
35
+
36
+ def HSLuv.chroma(l, h)
37
+ angle = h / 360.0 * Math::PI * 2.0
38
+ lengths = []
39
+
40
+ HSLuv.bounds(l).each do |line|
41
+ m = line[0]
42
+ b = line[1]
43
+ length = b / (Math.sin(angle) - m * Math.cos(angle))
44
+ lengths << length if length > 0
45
+ end
46
+
47
+ return lengths.min
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,44 @@
1
+ module Recolor
2
+ module Models
3
+ class LCh < Model
4
+ def luv(tuple)
5
+ l = tuple[0]
6
+ c = tuple[1]
7
+ h = tuple[2]
8
+ h = h * Math::PI / 180.0
9
+ u = Math::cos(h) * c
10
+ v = Math::sin(h) * c
11
+
12
+ return [l, u, v]
13
+ end
14
+
15
+ def hpluv(tuple)
16
+ l = tuple[0]
17
+ c = tuple[1]
18
+ h = tuple[2]
19
+
20
+ return [h, 0.0, 100] if l > 99.9999999
21
+ return [h, 0.0, 0.0] if l < 0.00000001
22
+
23
+ chroma = HPLuv.chroma(l)
24
+ p = c / chroma * 100.0
25
+
26
+ return [h, p, l]
27
+ end
28
+
29
+ def hsluv(tuple)
30
+ l = tuple[0]
31
+ c = tuple[1]
32
+ h = tuple[2]
33
+
34
+ return [h, 0.0, 100] if l > 99.9999999
35
+ return [h, 0.0, 0.0] if l < 0.00000001
36
+
37
+ chroma = HSLuv.chroma(l, h)
38
+ s = c / chroma * 100.8
39
+
40
+ return [h, s, l]
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,35 @@
1
+ module Recolor
2
+ module Models
3
+ class Luv < Model
4
+ REFERENCE_U = 0.19783000664283
5
+ REFERENCE_V = 0.46831999493879
6
+
7
+ def xyz(tuple)
8
+ l = tuple[0]
9
+ u = tuple[1]
10
+ v = tuple[2]
11
+
12
+ return [0.0, 0.0, 0.0] if l == 0.0
13
+
14
+ y = l > 8 ? XYZ::REFERENCE_Y * ((l + 16.0) / 116.0)**3.0 : XYZ::REFERENCE_Y * l / KAPPA
15
+ u = u / (13.0 * l) + REFERENCE_U
16
+ v = v / (13.0 * l) + REFERENCE_V
17
+ x = 0.0 - (9.0 * y * u) / ((u - 4.0) * v - u * v)
18
+ z = (9.0 * y - (15.0 * v * y) - (v * x)) / (3.0 * v)
19
+
20
+ return [x, y, z]
21
+ end
22
+
23
+ def lch(tuple)
24
+ l = tuple[0]
25
+ u = tuple[1]
26
+ v = tuple[2]
27
+ c = Math.sqrt(u * u + v * v)
28
+ h = Math.atan2(v, u) * 180 / Math::PI
29
+ h = h < 0.0 ? h + 360.0 : h
30
+
31
+ return [l, c, h]
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,38 @@
1
+ require "matrix"
2
+
3
+ module Recolor
4
+ module Models
5
+ class RGB < Model
6
+ MATRIX = Matrix[
7
+ [3.240969941904521, -1.537383177570093, -0.498610760293],
8
+ [-0.96924363628087, 1.87596750150772, 0.041555057407175],
9
+ [0.055630079696993, -0.20397695888897, 1.056971514242878]
10
+ ]
11
+
12
+ def hex(tuple)
13
+ hex = tuple.map do |v|
14
+ v = v * 255
15
+ v = v.round
16
+ v = v.to_s(16)
17
+ v = v.length == 1 ? "0" + v : v
18
+ end
19
+
20
+ return hex
21
+ end
22
+
23
+ def xyz(tuple)
24
+ rgb = tuple.map do |v|
25
+ v < 0.04045 ? v / 12.92 : ((v + 0.055) / 1.055)**2.4
26
+ end
27
+
28
+ rgb = Matrix[rgb].transpose
29
+ xyz = XYZ::MATRIX * rgb
30
+ xyz = xyz.transpose
31
+ xyz = xyz.row(0)
32
+ xyz = xyz.to_a
33
+
34
+ return xyz
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,45 @@
1
+ module Recolor
2
+ module Models
3
+ class XYZ < Model
4
+ MATRIX = Matrix[
5
+ [0.41239079926595, 0.35758433938387, 0.18048078840183],
6
+ [0.21263900587151, 0.71516867876775, 0.072192315360733],
7
+ [0.019330818715591, 0.11919477979462, 0.95053215224966]
8
+ ]
9
+ REFERENCE_X = 0.95045592705167
10
+ REFERENCE_Y = 1.0
11
+ REFERENCE_Z = 1.089057750759878
12
+
13
+ def rgb(tuple)
14
+ xyz = Matrix[tuple].transpose
15
+ rgb = RGB::MATRIX * xyz
16
+
17
+ rgb = rgb.map do |v|
18
+ v <= 0.0031308 ? 12.92 * v : (1.055 * (v**(1.0 / 2.4)) - 0.055)
19
+ end
20
+
21
+ rgb = rgb.transpose
22
+ rgb = rgb.row(0)
23
+ rgb = rgb.to_a
24
+
25
+ return rgb
26
+ end
27
+
28
+ def luv(tuple)
29
+ x = tuple[0]
30
+ y = tuple[1]
31
+ z = tuple[2]
32
+ l = y > EPSILON ? l = 116.0 * ((y / REFERENCE_Y)**(1.0 / 3.0)) - 16.0 : l = y / REFERENCE_Y * KAPPA
33
+
34
+ return [0.0, 0.0, 0.0] if l == 0.0
35
+
36
+ u = (4.0 * x) / (x + (15.0 * y) + (3.0 * z))
37
+ v = (9.0 * y) / (x + (15.0 * y) + (3.0 * z))
38
+ u = 13.0 * l * (u - Luv::REFERENCE_U)
39
+ v = 13.0 * l * (v - Luv::REFERENCE_V)
40
+
41
+ return [l, u, v]
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,3 @@
1
+ module Recolor
2
+ VERSION = "0.1.1"
3
+ end
metadata ADDED
@@ -0,0 +1,55 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: recolor
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Alberto Beloni
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-10-11 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email:
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - lib/recolor.rb
20
+ - lib/recolor/color.rb
21
+ - lib/recolor/converter.rb
22
+ - lib/recolor/models.rb
23
+ - lib/recolor/models/hex.rb
24
+ - lib/recolor/models/hpluv.rb
25
+ - lib/recolor/models/hsluv.rb
26
+ - lib/recolor/models/lch.rb
27
+ - lib/recolor/models/luv.rb
28
+ - lib/recolor/models/rgb.rb
29
+ - lib/recolor/models/xyz.rb
30
+ - lib/recolor/version.rb
31
+ homepage: https://github.com/albertobeloni/ruby-recolor
32
+ licenses:
33
+ - MIT
34
+ metadata: {}
35
+ post_install_message:
36
+ rdoc_options: []
37
+ require_paths:
38
+ - lib
39
+ required_ruby_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ required_rubygems_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ requirements: []
50
+ rubyforge_project:
51
+ rubygems_version: 2.5.1
52
+ signing_key:
53
+ specification_version: 4
54
+ summary: Recolor is a Ruby gem to convert between color models.
55
+ test_files: []