tincture 1.0.0 → 1.1.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 +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +1 -1
- data/lib/tincture/color/comparison.rb +2 -2
- data/lib/tincture/color/contrast.rb +9 -4
- data/lib/tincture/color/hsl.rb +3 -3
- data/lib/tincture/color/named_colors.rb +159 -0
- data/lib/tincture/color/oklab.rb +5 -7
- data/lib/tincture/color/parsing.rb +2 -7
- data/lib/tincture/color.rb +7 -4
- data/lib/tincture/color_validator.rb +1 -1
- data/lib/tincture/difference.rb +1 -1
- data/lib/tincture/version.rb +1 -1
- data/lib/tincture.rb +3 -0
- metadata +2 -2
- data/lib/tincture/named_colors.yml +0 -150
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 582ad42336a7e115f7ae13229231c0adb6e107d0ba1fcf2c4ebf118a9060d87a
|
|
4
|
+
data.tar.gz: 11697f93d17a93794af08edbdaa7d47bbc93cb2385ffccc9216b1c3596776d5d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 17b562aac3e4ce4bacd5a21285d66cc6e62d461cbbb1f3ab5d5bdd846cc613c30284402b754a9b0a0d7b6aa9d72f1fec178ed47f657898fef8069f3beace291e
|
|
7
|
+
data.tar.gz: 155f3cf6e300659f61f3a2ed6f2c395eb68f13f2f95432fe93d368029c32b6b463dde1c8be775a89f9ae3f4c0e6a71958a7d263e3e8715e936fbc903a9e826ac
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.1.0 (2026-10-21)
|
|
4
|
+
|
|
5
|
+
- Performance: `require "tincture"` is about 5 times faster, 10 ms down to 2 ms. Named colours now live in a Ruby hash, so loading the gem no longer loads YAML.
|
|
6
|
+
- Performance: `luminance`, `contrast_ratio`, `contrast_color` and `difference` are 15–50% faster. They look up each channel's linear value in a table and no longer compute a power. Results are unchanged.
|
|
7
|
+
- Performance: parsing a hex colour is about 30% faster, and `hex` (so also `to_s`, `as_json` and saving a `:color` attribute) is about twice as fast.
|
|
8
|
+
- Performance: `nearest_readable_on` is about 6 times faster, 224 µs down to 37 µs. It converts the colour and black or white to Oklab once per search, not on every step, and it searches 2¹⁶ steps toward black or white rather than every float. About 0.4% of results now land one 8-bit step further from the original colour. They still pass.
|
|
9
|
+
|
|
3
10
|
## 1.0.0 (2026-10-21)
|
|
4
11
|
|
|
5
12
|
- `Tincture::Color` parses CSS hex, named, `rgb()`, `hsl()`, `hwb()`, `oklab()` and `oklch()` colours, and converts between them and HSV.
|
data/README.md
CHANGED
|
@@ -169,6 +169,6 @@ bundle exec rake # tests and RuboCop
|
|
|
169
169
|
bundle exec rake rdoc # API docs in doc/
|
|
170
170
|
```
|
|
171
171
|
|
|
172
|
-
To release, set the version in `lib/tincture/version.rb`, date the changelog entry, commit, and push a `vX.Y.Z` tag. GitHub Actions runs the checks
|
|
172
|
+
To release, set the version in `lib/tincture/version.rb`, date the changelog entry, commit, and push a `vX.Y.Z` tag. GitHub Actions runs the checks, publishes the gem to rubygems.org through trusted publishing, and creates a GitHub release with that changelog entry as its notes.
|
|
173
173
|
|
|
174
174
|
Comments are Markdown. Method types are inline RBS (`#: (String) -> Color`), which RDoc shows on each method.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Tincture
|
|
4
|
-
class Color
|
|
4
|
+
class Color # rubocop:disable Style/Documentation
|
|
5
5
|
# How different two colours look. The formulas live in
|
|
6
6
|
# Tincture::Difference. Mixed into Color.
|
|
7
7
|
module Comparison
|
|
@@ -28,7 +28,7 @@ module Tincture
|
|
|
28
28
|
protected
|
|
29
29
|
|
|
30
30
|
# CIELAB against the D65 white point, as sRGB tools usually report it.
|
|
31
|
-
def lab_components # :nodoc:
|
|
31
|
+
def lab_components # :nodoc: # rubocop:disable Metrics/AbcSize
|
|
32
32
|
red, green, blue = linear_rgb
|
|
33
33
|
|
|
34
34
|
x, y, z = [
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Tincture
|
|
4
|
-
class Color
|
|
4
|
+
class Color # rubocop:disable Style/Documentation
|
|
5
5
|
# WCAG 2 minimum contrast ratios.
|
|
6
6
|
WCAG_RATIOS = { aa: { normal: 4.5, large: 3.0 }, aaa: { normal: 7.0, large: 4.5 } }.freeze
|
|
7
7
|
|
|
@@ -18,6 +18,8 @@ module Tincture
|
|
|
18
18
|
# WCAG 2 contrast, and picking text colours that read on a background.
|
|
19
19
|
# Mixed into Color.
|
|
20
20
|
module Contrast
|
|
21
|
+
MIX_STEPS = 2**16 # :nodoc:
|
|
22
|
+
|
|
21
23
|
# Added to Color itself.
|
|
22
24
|
module ClassMethods
|
|
23
25
|
# Scores for #contrast_color methods other than `:oklab`, keyed by
|
|
@@ -138,8 +140,11 @@ module Tincture
|
|
|
138
140
|
# The smallest mix toward `extreme` that passes the block. Assumes the
|
|
139
141
|
# block fails here and passes at `extreme`.
|
|
140
142
|
def nearest_mix_toward(extreme)
|
|
141
|
-
|
|
142
|
-
|
|
143
|
+
start = oklab_components
|
|
144
|
+
finish = extreme.oklab_components
|
|
145
|
+
|
|
146
|
+
step = (0..MIX_STEPS).bsearch { |candidate| yield mixed_oklab(start, finish, candidate.fdiv(MIX_STEPS)) }
|
|
147
|
+
mixed_oklab(start, finish, step.fdiv(MIX_STEPS))
|
|
143
148
|
end
|
|
144
149
|
|
|
145
150
|
def contrast_scorer(method)
|
|
@@ -150,7 +155,7 @@ module Tincture
|
|
|
150
155
|
end
|
|
151
156
|
|
|
152
157
|
def oklab_contrast_color(candidates)
|
|
153
|
-
if candidates.sort_by(&:luminance) == [BLACK, WHITE]
|
|
158
|
+
if candidates.sort_by(&:luminance) == [BLACK, WHITE] # rubocop:disable Style/GuardClause
|
|
154
159
|
oklab_components.first > OKLAB_CONTRAST_THRESHOLD ? BLACK : WHITE
|
|
155
160
|
else
|
|
156
161
|
raise ArgumentError, 'method: :oklab picks between black and white only'
|
data/lib/tincture/color/hsl.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Tincture
|
|
4
|
-
class Color
|
|
4
|
+
class Color # rubocop:disable Style/Documentation
|
|
5
5
|
# HSL and its relatives HWB and HSV, which share its hue angle. Mixed into
|
|
6
6
|
# Color.
|
|
7
7
|
module Hsl
|
|
@@ -21,7 +21,7 @@ module Tincture
|
|
|
21
21
|
# give a grey.
|
|
22
22
|
#
|
|
23
23
|
#: (Numeric hue, Numeric whiteness, Numeric blackness, ?Numeric alpha) -> Color
|
|
24
|
-
def hwb(hue, whiteness, blackness, alpha = 1.0)
|
|
24
|
+
def hwb(hue, whiteness, blackness, alpha = 1.0) # rubocop:disable Metrics/AbcSize
|
|
25
25
|
whiteness = whiteness.clamp(0, 100) / 100.0
|
|
26
26
|
blackness = blackness.clamp(0, 100) / 100.0
|
|
27
27
|
|
|
@@ -101,7 +101,7 @@ module Tincture
|
|
|
101
101
|
|
|
102
102
|
private
|
|
103
103
|
|
|
104
|
-
def hue
|
|
104
|
+
def hue # rubocop:disable Metrics/AbcSize
|
|
105
105
|
red, green, blue = channel_fractions
|
|
106
106
|
max, min = channel_fractions.minmax.reverse
|
|
107
107
|
delta = max - min
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Tincture
|
|
4
|
+
class Color # rubocop:disable Metrics/ClassLength
|
|
5
|
+
# CSS named colours, keyed by lowercase name, from
|
|
6
|
+
# [CSS Color 4](https://www.w3.org/TR/css-color-4/#named-colors).
|
|
7
|
+
NAMED = {
|
|
8
|
+
'aliceblue' => '#f0f8ff',
|
|
9
|
+
'antiquewhite' => '#faebd7',
|
|
10
|
+
'aqua' => '#00ffff',
|
|
11
|
+
'aquamarine' => '#7fffd4',
|
|
12
|
+
'azure' => '#f0ffff',
|
|
13
|
+
'beige' => '#f5f5dc',
|
|
14
|
+
'bisque' => '#ffe4c4',
|
|
15
|
+
'black' => '#000000',
|
|
16
|
+
'blanchedalmond' => '#ffebcd',
|
|
17
|
+
'blue' => '#0000ff',
|
|
18
|
+
'blueviolet' => '#8a2be2',
|
|
19
|
+
'brown' => '#a52a2a',
|
|
20
|
+
'burlywood' => '#deb887',
|
|
21
|
+
'cadetblue' => '#5f9ea0',
|
|
22
|
+
'chartreuse' => '#7fff00',
|
|
23
|
+
'chocolate' => '#d2691e',
|
|
24
|
+
'coral' => '#ff7f50',
|
|
25
|
+
'cornflowerblue' => '#6495ed',
|
|
26
|
+
'cornsilk' => '#fff8dc',
|
|
27
|
+
'crimson' => '#dc143c',
|
|
28
|
+
'cyan' => '#00ffff',
|
|
29
|
+
'darkblue' => '#00008b',
|
|
30
|
+
'darkcyan' => '#008b8b',
|
|
31
|
+
'darkgoldenrod' => '#b8860b',
|
|
32
|
+
'darkgray' => '#a9a9a9',
|
|
33
|
+
'darkgreen' => '#006400',
|
|
34
|
+
'darkgrey' => '#a9a9a9',
|
|
35
|
+
'darkkhaki' => '#bdb76b',
|
|
36
|
+
'darkmagenta' => '#8b008b',
|
|
37
|
+
'darkolivegreen' => '#556b2f',
|
|
38
|
+
'darkorange' => '#ff8c00',
|
|
39
|
+
'darkorchid' => '#9932cc',
|
|
40
|
+
'darkred' => '#8b0000',
|
|
41
|
+
'darksalmon' => '#e9967a',
|
|
42
|
+
'darkseagreen' => '#8fbc8f',
|
|
43
|
+
'darkslateblue' => '#483d8b',
|
|
44
|
+
'darkslategray' => '#2f4f4f',
|
|
45
|
+
'darkslategrey' => '#2f4f4f',
|
|
46
|
+
'darkturquoise' => '#00ced1',
|
|
47
|
+
'darkviolet' => '#9400d3',
|
|
48
|
+
'deeppink' => '#ff1493',
|
|
49
|
+
'deepskyblue' => '#00bfff',
|
|
50
|
+
'dimgray' => '#696969',
|
|
51
|
+
'dimgrey' => '#696969',
|
|
52
|
+
'dodgerblue' => '#1e90ff',
|
|
53
|
+
'firebrick' => '#b22222',
|
|
54
|
+
'floralwhite' => '#fffaf0',
|
|
55
|
+
'forestgreen' => '#228b22',
|
|
56
|
+
'fuchsia' => '#ff00ff',
|
|
57
|
+
'gainsboro' => '#dcdcdc',
|
|
58
|
+
'ghostwhite' => '#f8f8ff',
|
|
59
|
+
'gold' => '#ffd700',
|
|
60
|
+
'goldenrod' => '#daa520',
|
|
61
|
+
'gray' => '#808080',
|
|
62
|
+
'green' => '#008000',
|
|
63
|
+
'greenyellow' => '#adff2f',
|
|
64
|
+
'grey' => '#808080',
|
|
65
|
+
'honeydew' => '#f0fff0',
|
|
66
|
+
'hotpink' => '#ff69b4',
|
|
67
|
+
'indianred' => '#cd5c5c',
|
|
68
|
+
'indigo' => '#4b0082',
|
|
69
|
+
'ivory' => '#fffff0',
|
|
70
|
+
'khaki' => '#f0e68c',
|
|
71
|
+
'lavender' => '#e6e6fa',
|
|
72
|
+
'lavenderblush' => '#fff0f5',
|
|
73
|
+
'lawngreen' => '#7cfc00',
|
|
74
|
+
'lemonchiffon' => '#fffacd',
|
|
75
|
+
'lightblue' => '#add8e6',
|
|
76
|
+
'lightcoral' => '#f08080',
|
|
77
|
+
'lightcyan' => '#e0ffff',
|
|
78
|
+
'lightgoldenrodyellow' => '#fafad2',
|
|
79
|
+
'lightgray' => '#d3d3d3',
|
|
80
|
+
'lightgreen' => '#90ee90',
|
|
81
|
+
'lightgrey' => '#d3d3d3',
|
|
82
|
+
'lightpink' => '#ffb6c1',
|
|
83
|
+
'lightsalmon' => '#ffa07a',
|
|
84
|
+
'lightseagreen' => '#20b2aa',
|
|
85
|
+
'lightskyblue' => '#87cefa',
|
|
86
|
+
'lightslategray' => '#778899',
|
|
87
|
+
'lightslategrey' => '#778899',
|
|
88
|
+
'lightsteelblue' => '#b0c4de',
|
|
89
|
+
'lightyellow' => '#ffffe0',
|
|
90
|
+
'lime' => '#00ff00',
|
|
91
|
+
'limegreen' => '#32cd32',
|
|
92
|
+
'linen' => '#faf0e6',
|
|
93
|
+
'magenta' => '#ff00ff',
|
|
94
|
+
'maroon' => '#800000',
|
|
95
|
+
'mediumaquamarine' => '#66cdaa',
|
|
96
|
+
'mediumblue' => '#0000cd',
|
|
97
|
+
'mediumorchid' => '#ba55d3',
|
|
98
|
+
'mediumpurple' => '#9370db',
|
|
99
|
+
'mediumseagreen' => '#3cb371',
|
|
100
|
+
'mediumslateblue' => '#7b68ee',
|
|
101
|
+
'mediumspringgreen' => '#00fa9a',
|
|
102
|
+
'mediumturquoise' => '#48d1cc',
|
|
103
|
+
'mediumvioletred' => '#c71585',
|
|
104
|
+
'midnightblue' => '#191970',
|
|
105
|
+
'mintcream' => '#f5fffa',
|
|
106
|
+
'mistyrose' => '#ffe4e1',
|
|
107
|
+
'moccasin' => '#ffe4b5',
|
|
108
|
+
'navajowhite' => '#ffdead',
|
|
109
|
+
'navy' => '#000080',
|
|
110
|
+
'oldlace' => '#fdf5e6',
|
|
111
|
+
'olive' => '#808000',
|
|
112
|
+
'olivedrab' => '#6b8e23',
|
|
113
|
+
'orange' => '#ffa500',
|
|
114
|
+
'orangered' => '#ff4500',
|
|
115
|
+
'orchid' => '#da70d6',
|
|
116
|
+
'palegoldenrod' => '#eee8aa',
|
|
117
|
+
'palegreen' => '#98fb98',
|
|
118
|
+
'paleturquoise' => '#afeeee',
|
|
119
|
+
'palevioletred' => '#db7093',
|
|
120
|
+
'papayawhip' => '#ffefd5',
|
|
121
|
+
'peachpuff' => '#ffdab9',
|
|
122
|
+
'peru' => '#cd853f',
|
|
123
|
+
'pink' => '#ffc0cb',
|
|
124
|
+
'plum' => '#dda0dd',
|
|
125
|
+
'powderblue' => '#b0e0e6',
|
|
126
|
+
'purple' => '#800080',
|
|
127
|
+
'rebeccapurple' => '#663399',
|
|
128
|
+
'red' => '#ff0000',
|
|
129
|
+
'rosybrown' => '#bc8f8f',
|
|
130
|
+
'royalblue' => '#4169e1',
|
|
131
|
+
'saddlebrown' => '#8b4513',
|
|
132
|
+
'salmon' => '#fa8072',
|
|
133
|
+
'sandybrown' => '#f4a460',
|
|
134
|
+
'seagreen' => '#2e8b57',
|
|
135
|
+
'seashell' => '#fff5ee',
|
|
136
|
+
'sienna' => '#a0522d',
|
|
137
|
+
'silver' => '#c0c0c0',
|
|
138
|
+
'skyblue' => '#87ceeb',
|
|
139
|
+
'slateblue' => '#6a5acd',
|
|
140
|
+
'slategray' => '#708090',
|
|
141
|
+
'slategrey' => '#708090',
|
|
142
|
+
'snow' => '#fffafa',
|
|
143
|
+
'springgreen' => '#00ff7f',
|
|
144
|
+
'steelblue' => '#4682b4',
|
|
145
|
+
'tan' => '#d2b48c',
|
|
146
|
+
'teal' => '#008080',
|
|
147
|
+
'thistle' => '#d8bfd8',
|
|
148
|
+
'tomato' => '#ff6347',
|
|
149
|
+
'transparent' => '#00000000',
|
|
150
|
+
'turquoise' => '#40e0d0',
|
|
151
|
+
'violet' => '#ee82ee',
|
|
152
|
+
'wheat' => '#f5deb3',
|
|
153
|
+
'white' => '#ffffff',
|
|
154
|
+
'whitesmoke' => '#f5f5f5',
|
|
155
|
+
'yellow' => '#ffff00',
|
|
156
|
+
'yellowgreen' => '#9acd32'
|
|
157
|
+
}.transform_values { parse(it) }.freeze
|
|
158
|
+
end
|
|
159
|
+
end
|
data/lib/tincture/color/oklab.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Tincture
|
|
4
|
-
class Color
|
|
4
|
+
class Color # rubocop:disable Style/Documentation
|
|
5
5
|
# Oklab and its cylindrical form Oklch, where equal steps look equally
|
|
6
6
|
# different. Mixed into Color.
|
|
7
7
|
module Oklab
|
|
@@ -11,7 +11,7 @@ module Tincture
|
|
|
11
11
|
# and `b` (blue–yellow) axes.
|
|
12
12
|
#
|
|
13
13
|
#: (Numeric lightness, Numeric green_red, Numeric blue_yellow, ?Numeric alpha) -> Color
|
|
14
|
-
def oklab(lightness, green_red, blue_yellow, alpha = 1.0)
|
|
14
|
+
def oklab(lightness, green_red, blue_yellow, alpha = 1.0) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
15
15
|
lightness = lightness.clamp(0, 1)
|
|
16
16
|
|
|
17
17
|
l, m, s = [
|
|
@@ -77,7 +77,7 @@ module Tincture
|
|
|
77
77
|
|
|
78
78
|
protected
|
|
79
79
|
|
|
80
|
-
def oklab_components # :nodoc:
|
|
80
|
+
def oklab_components # :nodoc: # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
81
81
|
red, green, blue = linear_rgb
|
|
82
82
|
|
|
83
83
|
l, m, s = [
|
|
@@ -95,10 +95,8 @@ module Tincture
|
|
|
95
95
|
|
|
96
96
|
private
|
|
97
97
|
|
|
98
|
-
def
|
|
99
|
-
lightness, a, b =
|
|
100
|
-
mine + ((theirs - mine) * amount)
|
|
101
|
-
end
|
|
98
|
+
def mixed_oklab(start, finish, amount)
|
|
99
|
+
lightness, a, b = start.zip(finish).map { |mine, theirs| mine + ((theirs - mine) * amount) }
|
|
102
100
|
Color.oklab(lightness, a, b, alpha)
|
|
103
101
|
end
|
|
104
102
|
end
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'yaml'
|
|
4
|
-
|
|
5
3
|
module Tincture
|
|
6
|
-
class Color
|
|
4
|
+
class Color # rubocop:disable Style/Documentation
|
|
7
5
|
# Reads CSS colour strings: hex, named colours and the `rgb()`, `hsl()`,
|
|
8
6
|
# `hwb()`, `oklab()` and `oklch()` functions. Extends Color, so its
|
|
9
7
|
# methods are called on the class: `Tincture::Color.parse`.
|
|
@@ -83,7 +81,7 @@ module Tincture
|
|
|
83
81
|
return unless digits
|
|
84
82
|
|
|
85
83
|
digits = digits.chars.map { it * 2 }.join if digits.length <= 4
|
|
86
|
-
red, green, blue, alpha = digits.
|
|
84
|
+
red, green, blue, alpha = [digits].pack('H*').bytes
|
|
87
85
|
rgb(red, green, blue, (alpha || 255) / 255.0)
|
|
88
86
|
end
|
|
89
87
|
|
|
@@ -137,8 +135,5 @@ module Tincture
|
|
|
137
135
|
end
|
|
138
136
|
|
|
139
137
|
extend Parsing
|
|
140
|
-
|
|
141
|
-
# CSS named colours, keyed by lowercase name.
|
|
142
|
-
NAMED = YAML.load_file(File.expand_path('../named_colors.yml', __dir__)).transform_values { parse(it) }.freeze
|
|
143
138
|
end
|
|
144
139
|
end
|
data/lib/tincture/color.rb
CHANGED
|
@@ -23,6 +23,11 @@ module Tincture
|
|
|
23
23
|
# Conversions follow [CSS Color 4](https://www.w3.org/TR/css-color-4/) and
|
|
24
24
|
# [Oklab](https://bottosson.github.io/posts/oklab/).
|
|
25
25
|
class Color < Data.define(:red, :green, :blue, :alpha)
|
|
26
|
+
LINEAR_CHANNELS = Array.new(256) do |byte| # :nodoc:
|
|
27
|
+
fraction = byte / 255.0
|
|
28
|
+
fraction <= 0.04045 ? fraction / 12.92 : ((fraction + 0.055) / 1.055)**2.4
|
|
29
|
+
end.freeze
|
|
30
|
+
|
|
26
31
|
# Builds a colour from 0–255 channels and a 0–1 alpha. Out-of-range
|
|
27
32
|
# values clamp, as they do in CSS.
|
|
28
33
|
#
|
|
@@ -37,7 +42,7 @@ module Tincture
|
|
|
37
42
|
#: () -> String
|
|
38
43
|
def hex
|
|
39
44
|
bytes = opaque? ? rgb : [*rgb, alpha_byte]
|
|
40
|
-
"##{bytes.
|
|
45
|
+
"##{bytes.pack('C*').unpack1('H*')}"
|
|
41
46
|
end
|
|
42
47
|
|
|
43
48
|
alias to_s hex
|
|
@@ -68,9 +73,7 @@ module Tincture
|
|
|
68
73
|
|
|
69
74
|
def channel_fractions = rgb.map { it / 255.0 }
|
|
70
75
|
|
|
71
|
-
def linear_rgb
|
|
72
|
-
channel_fractions.map { it <= 0.04045 ? it / 12.92 : ((it + 0.055) / 1.055)**2.4 }
|
|
73
|
-
end
|
|
76
|
+
def linear_rgb = rgb.map { LINEAR_CHANNELS[it] }
|
|
74
77
|
|
|
75
78
|
# Adding 0.0 turns -0.0 into 0.0, so CSS never shows "-0".
|
|
76
79
|
def rounded(number, digits) = number.round(digits) + 0.0
|
|
@@ -14,7 +14,7 @@ module ActiveModel # :nodoc:
|
|
|
14
14
|
MESSAGE = 'is not a valid color'
|
|
15
15
|
|
|
16
16
|
def validate_each(record, attribute, value) # :nodoc:
|
|
17
|
-
if value.nil? && record.read_attribute_before_type_cast(attribute).present?
|
|
17
|
+
if value.nil? && record.read_attribute_before_type_cast(attribute).present? # rubocop:disable Style/GuardClause
|
|
18
18
|
record.errors.add(attribute, :invalid_color, message: options.fetch(:message, self.class::MESSAGE))
|
|
19
19
|
end
|
|
20
20
|
end
|
data/lib/tincture/difference.rb
CHANGED
|
@@ -21,7 +21,7 @@ module Tincture
|
|
|
21
21
|
# with the weighting factors kL, kC and kH all 1.
|
|
22
22
|
#
|
|
23
23
|
#: ([Float, Float, Float] first, [Float, Float, Float] second) -> Float
|
|
24
|
-
def ciede2000(first, second)
|
|
24
|
+
def ciede2000(first, second) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
25
25
|
(l1, a1, b1), (l2, a2, b2) = first, second
|
|
26
26
|
|
|
27
27
|
chroma_mean = (Math.hypot(a1, b1) + Math.hypot(a2, b2)) / 2
|
data/lib/tincture/version.rb
CHANGED
data/lib/tincture.rb
CHANGED
|
@@ -4,6 +4,7 @@ require_relative 'tincture/version'
|
|
|
4
4
|
require_relative 'tincture/difference'
|
|
5
5
|
require_relative 'tincture/color'
|
|
6
6
|
require_relative 'tincture/color/parsing'
|
|
7
|
+
require_relative 'tincture/color/named_colors'
|
|
7
8
|
require_relative 'tincture/color/hsl'
|
|
8
9
|
require_relative 'tincture/color/oklab'
|
|
9
10
|
require_relative 'tincture/color/contrast'
|
|
@@ -25,4 +26,6 @@ module Tincture
|
|
|
25
26
|
InvalidColour = InvalidColor
|
|
26
27
|
end
|
|
27
28
|
|
|
29
|
+
# :nocov:
|
|
28
30
|
require_relative 'tincture/railtie' if defined?(Rails::Railtie)
|
|
31
|
+
# :nocov:
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tincture
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andy Croll
|
|
@@ -26,11 +26,11 @@ files:
|
|
|
26
26
|
- lib/tincture/color/comparison.rb
|
|
27
27
|
- lib/tincture/color/contrast.rb
|
|
28
28
|
- lib/tincture/color/hsl.rb
|
|
29
|
+
- lib/tincture/color/named_colors.rb
|
|
29
30
|
- lib/tincture/color/oklab.rb
|
|
30
31
|
- lib/tincture/color/parsing.rb
|
|
31
32
|
- lib/tincture/color_validator.rb
|
|
32
33
|
- lib/tincture/difference.rb
|
|
33
|
-
- lib/tincture/named_colors.yml
|
|
34
34
|
- lib/tincture/railtie.rb
|
|
35
35
|
- lib/tincture/type.rb
|
|
36
36
|
- lib/tincture/version.rb
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
# CSS Color 4 named colors: https://www.w3.org/TR/css-color-4/#named-colors
|
|
2
|
-
aliceblue: "#f0f8ff"
|
|
3
|
-
antiquewhite: "#faebd7"
|
|
4
|
-
aqua: "#00ffff"
|
|
5
|
-
aquamarine: "#7fffd4"
|
|
6
|
-
azure: "#f0ffff"
|
|
7
|
-
beige: "#f5f5dc"
|
|
8
|
-
bisque: "#ffe4c4"
|
|
9
|
-
black: "#000000"
|
|
10
|
-
blanchedalmond: "#ffebcd"
|
|
11
|
-
blue: "#0000ff"
|
|
12
|
-
blueviolet: "#8a2be2"
|
|
13
|
-
brown: "#a52a2a"
|
|
14
|
-
burlywood: "#deb887"
|
|
15
|
-
cadetblue: "#5f9ea0"
|
|
16
|
-
chartreuse: "#7fff00"
|
|
17
|
-
chocolate: "#d2691e"
|
|
18
|
-
coral: "#ff7f50"
|
|
19
|
-
cornflowerblue: "#6495ed"
|
|
20
|
-
cornsilk: "#fff8dc"
|
|
21
|
-
crimson: "#dc143c"
|
|
22
|
-
cyan: "#00ffff"
|
|
23
|
-
darkblue: "#00008b"
|
|
24
|
-
darkcyan: "#008b8b"
|
|
25
|
-
darkgoldenrod: "#b8860b"
|
|
26
|
-
darkgray: "#a9a9a9"
|
|
27
|
-
darkgreen: "#006400"
|
|
28
|
-
darkgrey: "#a9a9a9"
|
|
29
|
-
darkkhaki: "#bdb76b"
|
|
30
|
-
darkmagenta: "#8b008b"
|
|
31
|
-
darkolivegreen: "#556b2f"
|
|
32
|
-
darkorange: "#ff8c00"
|
|
33
|
-
darkorchid: "#9932cc"
|
|
34
|
-
darkred: "#8b0000"
|
|
35
|
-
darksalmon: "#e9967a"
|
|
36
|
-
darkseagreen: "#8fbc8f"
|
|
37
|
-
darkslateblue: "#483d8b"
|
|
38
|
-
darkslategray: "#2f4f4f"
|
|
39
|
-
darkslategrey: "#2f4f4f"
|
|
40
|
-
darkturquoise: "#00ced1"
|
|
41
|
-
darkviolet: "#9400d3"
|
|
42
|
-
deeppink: "#ff1493"
|
|
43
|
-
deepskyblue: "#00bfff"
|
|
44
|
-
dimgray: "#696969"
|
|
45
|
-
dimgrey: "#696969"
|
|
46
|
-
dodgerblue: "#1e90ff"
|
|
47
|
-
firebrick: "#b22222"
|
|
48
|
-
floralwhite: "#fffaf0"
|
|
49
|
-
forestgreen: "#228b22"
|
|
50
|
-
fuchsia: "#ff00ff"
|
|
51
|
-
gainsboro: "#dcdcdc"
|
|
52
|
-
ghostwhite: "#f8f8ff"
|
|
53
|
-
gold: "#ffd700"
|
|
54
|
-
goldenrod: "#daa520"
|
|
55
|
-
gray: "#808080"
|
|
56
|
-
green: "#008000"
|
|
57
|
-
greenyellow: "#adff2f"
|
|
58
|
-
grey: "#808080"
|
|
59
|
-
honeydew: "#f0fff0"
|
|
60
|
-
hotpink: "#ff69b4"
|
|
61
|
-
indianred: "#cd5c5c"
|
|
62
|
-
indigo: "#4b0082"
|
|
63
|
-
ivory: "#fffff0"
|
|
64
|
-
khaki: "#f0e68c"
|
|
65
|
-
lavender: "#e6e6fa"
|
|
66
|
-
lavenderblush: "#fff0f5"
|
|
67
|
-
lawngreen: "#7cfc00"
|
|
68
|
-
lemonchiffon: "#fffacd"
|
|
69
|
-
lightblue: "#add8e6"
|
|
70
|
-
lightcoral: "#f08080"
|
|
71
|
-
lightcyan: "#e0ffff"
|
|
72
|
-
lightgoldenrodyellow: "#fafad2"
|
|
73
|
-
lightgray: "#d3d3d3"
|
|
74
|
-
lightgreen: "#90ee90"
|
|
75
|
-
lightgrey: "#d3d3d3"
|
|
76
|
-
lightpink: "#ffb6c1"
|
|
77
|
-
lightsalmon: "#ffa07a"
|
|
78
|
-
lightseagreen: "#20b2aa"
|
|
79
|
-
lightskyblue: "#87cefa"
|
|
80
|
-
lightslategray: "#778899"
|
|
81
|
-
lightslategrey: "#778899"
|
|
82
|
-
lightsteelblue: "#b0c4de"
|
|
83
|
-
lightyellow: "#ffffe0"
|
|
84
|
-
lime: "#00ff00"
|
|
85
|
-
limegreen: "#32cd32"
|
|
86
|
-
linen: "#faf0e6"
|
|
87
|
-
magenta: "#ff00ff"
|
|
88
|
-
maroon: "#800000"
|
|
89
|
-
mediumaquamarine: "#66cdaa"
|
|
90
|
-
mediumblue: "#0000cd"
|
|
91
|
-
mediumorchid: "#ba55d3"
|
|
92
|
-
mediumpurple: "#9370db"
|
|
93
|
-
mediumseagreen: "#3cb371"
|
|
94
|
-
mediumslateblue: "#7b68ee"
|
|
95
|
-
mediumspringgreen: "#00fa9a"
|
|
96
|
-
mediumturquoise: "#48d1cc"
|
|
97
|
-
mediumvioletred: "#c71585"
|
|
98
|
-
midnightblue: "#191970"
|
|
99
|
-
mintcream: "#f5fffa"
|
|
100
|
-
mistyrose: "#ffe4e1"
|
|
101
|
-
moccasin: "#ffe4b5"
|
|
102
|
-
navajowhite: "#ffdead"
|
|
103
|
-
navy: "#000080"
|
|
104
|
-
oldlace: "#fdf5e6"
|
|
105
|
-
olive: "#808000"
|
|
106
|
-
olivedrab: "#6b8e23"
|
|
107
|
-
orange: "#ffa500"
|
|
108
|
-
orangered: "#ff4500"
|
|
109
|
-
orchid: "#da70d6"
|
|
110
|
-
palegoldenrod: "#eee8aa"
|
|
111
|
-
palegreen: "#98fb98"
|
|
112
|
-
paleturquoise: "#afeeee"
|
|
113
|
-
palevioletred: "#db7093"
|
|
114
|
-
papayawhip: "#ffefd5"
|
|
115
|
-
peachpuff: "#ffdab9"
|
|
116
|
-
peru: "#cd853f"
|
|
117
|
-
pink: "#ffc0cb"
|
|
118
|
-
plum: "#dda0dd"
|
|
119
|
-
powderblue: "#b0e0e6"
|
|
120
|
-
purple: "#800080"
|
|
121
|
-
rebeccapurple: "#663399"
|
|
122
|
-
red: "#ff0000"
|
|
123
|
-
rosybrown: "#bc8f8f"
|
|
124
|
-
royalblue: "#4169e1"
|
|
125
|
-
saddlebrown: "#8b4513"
|
|
126
|
-
salmon: "#fa8072"
|
|
127
|
-
sandybrown: "#f4a460"
|
|
128
|
-
seagreen: "#2e8b57"
|
|
129
|
-
seashell: "#fff5ee"
|
|
130
|
-
sienna: "#a0522d"
|
|
131
|
-
silver: "#c0c0c0"
|
|
132
|
-
skyblue: "#87ceeb"
|
|
133
|
-
slateblue: "#6a5acd"
|
|
134
|
-
slategray: "#708090"
|
|
135
|
-
slategrey: "#708090"
|
|
136
|
-
snow: "#fffafa"
|
|
137
|
-
springgreen: "#00ff7f"
|
|
138
|
-
steelblue: "#4682b4"
|
|
139
|
-
tan: "#d2b48c"
|
|
140
|
-
teal: "#008080"
|
|
141
|
-
thistle: "#d8bfd8"
|
|
142
|
-
tomato: "#ff6347"
|
|
143
|
-
transparent: "#00000000"
|
|
144
|
-
turquoise: "#40e0d0"
|
|
145
|
-
violet: "#ee82ee"
|
|
146
|
-
wheat: "#f5deb3"
|
|
147
|
-
white: "#ffffff"
|
|
148
|
-
whitesmoke: "#f5f5f5"
|
|
149
|
-
yellow: "#ffff00"
|
|
150
|
-
yellowgreen: "#9acd32"
|