color_corrector 0.0.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.
- checksums.yaml +7 -0
- data/lib/color_corrector.rb +157 -0
- data/lib/color_corrector/color.rb +52 -0
- data/lib/color_corrector/version.rb +6 -0
- metadata +46 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e949065e4e833524707fd819b09f952e84805dba
|
4
|
+
data.tar.gz: 5db4477bf399c53f7459fd04df3a76f9710a7057
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 17221c17cecbca24f7707d81d575d8afdb396b8f41cb87a7ef6ca864aec62a720e996201d8183e376275c21c710f139c096a60aad1ef31586cba613218ffeb22
|
7
|
+
data.tar.gz: 8c8edb9e234148281c9100828b7017b777f2cbd61573a24330612373d521063c710e18dd981bd9c202a8a33dc2c880929517e956de2c47dd960244b737b51419
|
@@ -0,0 +1,157 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'color_corrector/color'
|
4
|
+
require 'color_corrector/version'
|
5
|
+
|
6
|
+
# # Color Corrector
|
7
|
+
module ColorCorrector
|
8
|
+
ONE_SIXTH = 1 / 6.0
|
9
|
+
ONE_THIRD = 1 / 3.0
|
10
|
+
TWO_THIRDS = 2 / 3.0
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def make_readable(background, foreground, level = 'AA', size = 'large')
|
14
|
+
until readable?(background, foreground, level, size)
|
15
|
+
background = if light?(foreground)
|
16
|
+
darken(background)
|
17
|
+
else
|
18
|
+
lighten(background)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
background
|
22
|
+
end
|
23
|
+
|
24
|
+
def readable?(background, foreground, level = 'AA', size = 'large')
|
25
|
+
ratio = contrast_ratio(background, foreground)
|
26
|
+
contrast = case [level, size]
|
27
|
+
when %w[AA large]
|
28
|
+
3
|
29
|
+
when %w[AAA small]
|
30
|
+
7
|
31
|
+
else # %w[AA small], %w[AAA large]
|
32
|
+
4.5
|
33
|
+
end
|
34
|
+
ratio >= contrast
|
35
|
+
end
|
36
|
+
|
37
|
+
def contrast_ratio(background, foreground)
|
38
|
+
background = background.delete('#')
|
39
|
+
foreground = foreground.delete('#')
|
40
|
+
ratio(background, foreground)
|
41
|
+
end
|
42
|
+
|
43
|
+
def darken(hex_color, amount = 0.01)
|
44
|
+
red, green, blue = hex_color.delete('#').scan(/../).map(&:hex)
|
45
|
+
hue, saturation, lightness = rgb_to_hsl(red, blue, green)
|
46
|
+
lightness -= amount
|
47
|
+
rgb = hsl_to_rgb(hue, saturation, lightness)
|
48
|
+
format '#%02x%02x%02x', *rgb
|
49
|
+
end
|
50
|
+
|
51
|
+
def lighten(hex_color, amount = 0.01)
|
52
|
+
red, green, blue = hex_color.delete('#').scan(/../).map(&:hex)
|
53
|
+
hue, saturation, lightness = rgb_to_hsl(red, blue, green)
|
54
|
+
lightness += amount
|
55
|
+
rgb = hsl_to_rgb(hue, saturation, lightness)
|
56
|
+
format '#%02x%02x%02x', *rgb
|
57
|
+
end
|
58
|
+
|
59
|
+
def rgb_to_hsl(red, blue, green)
|
60
|
+
components = [red, blue, green].map { |chroma| chroma / 255.0 }
|
61
|
+
max = components.max
|
62
|
+
min = components.min
|
63
|
+
red, blue, green = components
|
64
|
+
lightness = (max + min) / 2
|
65
|
+
|
66
|
+
if max == min
|
67
|
+
hue = saturation = 0
|
68
|
+
else
|
69
|
+
chroma = max - min
|
70
|
+
saturation =
|
71
|
+
lightness > 0.5 ? (chroma / (2 - max - min)) : (chroma / (max + min))
|
72
|
+
hue = case max
|
73
|
+
when red
|
74
|
+
(green - blue) / chroma + (green < blue ? 6 : 0)
|
75
|
+
when green
|
76
|
+
(blue - red) / chroma + 2
|
77
|
+
when blue
|
78
|
+
(red - green) / chroma + 4
|
79
|
+
end
|
80
|
+
hue /= 6
|
81
|
+
end
|
82
|
+
[hue, saturation, lightness]
|
83
|
+
end
|
84
|
+
|
85
|
+
# Variables papa, quebec and tango were originally designated by single
|
86
|
+
# letters but have been changed to match the NATO photonetic alphabet
|
87
|
+
def hsl_to_rgb(hue, saturation, lightness)
|
88
|
+
if saturation.zero?
|
89
|
+
red = green = blue = lightness
|
90
|
+
else
|
91
|
+
quebec = if lightness < 0.5
|
92
|
+
lightness * (1 + saturation)
|
93
|
+
else
|
94
|
+
lightness + saturation - lightness * saturation
|
95
|
+
end
|
96
|
+
papa = 2 * lightness - quebec
|
97
|
+
red, green, blue = [ONE_THIRD, 0, -ONE_THIRD].map do |offset|
|
98
|
+
hue_to_rgb papa, quebec, hue + offset
|
99
|
+
end
|
100
|
+
end
|
101
|
+
[red, green, blue].map { |component| (component * 255).round }
|
102
|
+
end
|
103
|
+
|
104
|
+
# :reek:FeatureEnvy
|
105
|
+
def hue_to_rgb(papa, quebec, tango)
|
106
|
+
tango = bound_hue_01(tango)
|
107
|
+
if tango < ONE_SIXTH
|
108
|
+
papa + (quebec - papa) * 6 * tango
|
109
|
+
elsif tango < 0.5 # (1 / 2.0)
|
110
|
+
quebec
|
111
|
+
elsif tango < TWO_THIRDS
|
112
|
+
papa + (quebec - papa) * (TWO_THIRDS - tango) * 6
|
113
|
+
else
|
114
|
+
papa
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def bound_hue_01(hue)
|
119
|
+
if hue.negative?
|
120
|
+
hue + 1
|
121
|
+
elsif hue > 1
|
122
|
+
hue - 1
|
123
|
+
else
|
124
|
+
hue
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# :reek:UncommunicativeVariableName and :reek:UncommunicativeParameterName
|
129
|
+
def ratio(rgb1, rgb2)
|
130
|
+
c1, c2 = [rgb1, rgb2].map { |rgb| Color.new(rgb) }
|
131
|
+
l1, l2 = [c1, c2].map(&:relative_luminance).sort
|
132
|
+
(l2 + 0.05) / (l1 + 0.05)
|
133
|
+
end
|
134
|
+
|
135
|
+
def relative_luminance(red, green, blue)
|
136
|
+
(0.2126 * f(red)) + (0.7152 * f(green)) + (0.0722 * f(blue))
|
137
|
+
end
|
138
|
+
|
139
|
+
# :reek:UncommunicativeVariableName and :reek:UncommunicativeMethodName
|
140
|
+
def f(component)
|
141
|
+
c = component / 255.0
|
142
|
+
c <= 0.03928 ? c : ((c + 0.055) / 1.055)**2.4
|
143
|
+
end
|
144
|
+
|
145
|
+
def light?(hex)
|
146
|
+
red, green, blue = hex.delete('#').scan(/../).map(&:hex)
|
147
|
+
luma = 0.2126 * red + 0.7152 * green + 0.0722 * blue
|
148
|
+
luma >= 128
|
149
|
+
end
|
150
|
+
|
151
|
+
def dark?(hex)
|
152
|
+
red, green, blue = hex.delete('#').scan(/../).map(&:hex)
|
153
|
+
luma = 0.2126 * red + 0.7152 * green + 0.0722 * blue
|
154
|
+
luma < 128
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Color Class
|
4
|
+
class Color
|
5
|
+
attr_reader :r, :g, :b
|
6
|
+
|
7
|
+
def initialize(*args)
|
8
|
+
input = args.size == 1 ? args[0] : args
|
9
|
+
@r, @g, @b = Color.rgb_from(input)
|
10
|
+
end
|
11
|
+
|
12
|
+
def relative_luminance
|
13
|
+
ColorCorrector.relative_luminance(r, g, b)
|
14
|
+
end
|
15
|
+
|
16
|
+
def ratio(color)
|
17
|
+
ColorCorrector.ratio(self, color)
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_rgb
|
21
|
+
[r, g, b]
|
22
|
+
end
|
23
|
+
|
24
|
+
class << self
|
25
|
+
def rgb_from(input)
|
26
|
+
case input
|
27
|
+
when String # hex code
|
28
|
+
raise 'Invalid hex code' unless input =~ /\A([0-9a-f]{3}){1,2}\z/i
|
29
|
+
rgb = if input.size == 3
|
30
|
+
input.split('').map { |h| h * 2 }
|
31
|
+
else
|
32
|
+
input.scan(/.{2}/)
|
33
|
+
end
|
34
|
+
rgb.map { |h| h.hex.to_i }
|
35
|
+
when Array # array of numbers
|
36
|
+
raise 'Invalid RGB array' unless input.size == 3
|
37
|
+
input.map(&:to_f)
|
38
|
+
when Hash
|
39
|
+
rgb = input.values_at(:r, :g, :b)
|
40
|
+
raise 'Invalid RGB hash' unless rgb.size == 3
|
41
|
+
rgb.map(&:to_f)
|
42
|
+
else
|
43
|
+
methods = [:r,:g, :b]
|
44
|
+
if methods.select { |m| input.respond_to?(m) }.size == methods.size
|
45
|
+
methods.map { |m| input.send(m) }
|
46
|
+
else
|
47
|
+
raise 'Invalid input'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
metadata
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: color_corrector
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Lukas Barry
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-08-30 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description:
|
14
|
+
email: lukasbbarry@gmail.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- lib/color_corrector.rb
|
20
|
+
- lib/color_corrector/color.rb
|
21
|
+
- lib/color_corrector/version.rb
|
22
|
+
homepage: https://github.com/LukasBarry/color_corrector
|
23
|
+
licenses:
|
24
|
+
- MIT
|
25
|
+
metadata: {}
|
26
|
+
post_install_message:
|
27
|
+
rdoc_options: []
|
28
|
+
require_paths:
|
29
|
+
- lib
|
30
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
requirements: []
|
41
|
+
rubyforge_project:
|
42
|
+
rubygems_version: 2.5.2
|
43
|
+
signing_key:
|
44
|
+
specification_version: 4
|
45
|
+
summary: Color Corrector allows you to revise your colors to be WCAG compliant
|
46
|
+
test_files: []
|