color_contrast_calc 0.3.0 → 0.4.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
  SHA1:
3
- metadata.gz: 624186d8778091959fe8526cba79cbe56708c16d
4
- data.tar.gz: 2961fad47dfc7afa4b4893dd3d7b0995a97e5601
3
+ metadata.gz: 513b56ff5dca5ea3a6a7343a4cc5111a19c976e2
4
+ data.tar.gz: 9958f22f8d1474b93a3573ce728ffe6e41abe6d7
5
5
  SHA512:
6
- metadata.gz: a28e5639b5db61cb0a722a1802b6969d1bb2c20d60783efd9242094f76e984987bd16330d37ac2f36f480c25b81b2679617035159dde4f74798c101a7b7e0de8
7
- data.tar.gz: 5f95b64878aba232ed3923849de80776c33229a899fb76014ed397fa3918f89ab869cc690546cbe49ee68f8f970944f4e315ef23beb29fdfae0391f26b1efdcc
6
+ metadata.gz: ebf3189b2a716538c29fe3c3730e47f79d9a51fba4d53989269fe20f9a56e0225ee38e105936aa2c05844b3fb4925243feeefa9c670733975f82b46eabb15c2d
7
+ data.tar.gz: 5c6b613c861aaa290e31d1c1c710c6d7775beb742f43c896f25e7c10bf1b890cc7833ebe7f37b8b4c5727bc1ce68eb4ad9c8916f8bc853fc8f47d405ac2d34ec
data/README.ja.md CHANGED
@@ -174,7 +174,7 @@ The contrast ratio between #ffff00 and #9d6600 is 4.5121
174
174
  ### 例3: ある色のグレースケール
175
175
 
176
176
  ある色のグレースケールを得るために`ColorContrastCalc::Color` には
177
- `new_grayscale_color`というインスタンスメソッドがあります。
177
+ `with_grayscale`というインスタンスメソッドがあります。
178
178
 
179
179
  例えば次のコードを`grayscale.rb`として保存し:
180
180
 
@@ -185,8 +185,8 @@ yellow = ColorContrastCalc.color_from('yellow')
185
185
  orange = ColorContrastCalc.color_from('orange')
186
186
 
187
187
  report = 'The grayscale of %s is %s.'
188
- puts(format(report, yellow.hex, yellow.new_grayscale_color))
189
- puts(format(report, orange.hex, orange.new_grayscale_color))
188
+ puts(format(report, yellow.hex, yellow.with_grayscale))
189
+ puts(format(report, orange.hex, orange.with_grayscale))
190
190
  ```
191
191
 
192
192
  以下のように実行します:
@@ -197,9 +197,20 @@ The grayscale of #ffff00 is #ededed.
197
197
  The grayscale of #ffa500 is #acacac.
198
198
  ```
199
199
 
200
- また`new_grayscale_color`以外に、以下のインスタンスメッソドが
200
+ また`with_grayscale`以外に、以下のインスタンスメッソドが
201
201
  `ColorContrastCalc::Color`では利用できます。:
202
202
 
203
+ * `with_brightness`
204
+ * `with_contrast`
205
+ * `with_hue_rotate`
206
+ * `with_invert`
207
+ * `with_saturate`
208
+
209
+ #### 非推奨のメソッド
210
+
211
+ 以下のメソッドは非推奨であることにご注意下さい。
212
+
213
+ * `new_grayscale_color`
203
214
  * `new_brightness_color`
204
215
  * `new_contrast_color`
205
216
  * `new_hue_rotate_color`
data/README.md CHANGED
@@ -174,7 +174,7 @@ The contrast ratio between #ffff00 and #9d6600 is 4.5121
174
174
  ### Example 3: Grayscale of given colors
175
175
 
176
176
  For getting grayscale, `ColorContrastCalc::Color` has an instance method
177
- `new_grayscale_color`.
177
+ `with_grayscale`.
178
178
  For example, save the following code as `grayscale.rb`:
179
179
 
180
180
  ```ruby
@@ -184,8 +184,8 @@ yellow = ColorContrastCalc.color_from('yellow')
184
184
  orange = ColorContrastCalc.color_from('orange')
185
185
 
186
186
  report = 'The grayscale of %s is %s.'
187
- puts(format(report, yellow.hex, yellow.new_grayscale_color))
188
- puts(format(report, orange.hex, orange.new_grayscale_color))
187
+ puts(format(report, yellow.hex, yellow.with_grayscale))
188
+ puts(format(report, orange.hex, orange.with_grayscale))
189
189
  ```
190
190
 
191
191
  Then execute the script:
@@ -196,9 +196,20 @@ The grayscale of #ffff00 is #ededed.
196
196
  The grayscale of #ffa500 is #acacac.
197
197
  ```
198
198
 
199
- And other than `new_grayscale_color`, following instance methods
199
+ And other than `with_grayscale`, following instance methods
200
200
  are available for `ColorContrastCalc::Color`:
201
201
 
202
+ * `with_brightness`
203
+ * `with_contrast`
204
+ * `with_hue_rotate`
205
+ * `with_invert`
206
+ * `with_saturate`
207
+
208
+ #### Deprecated instance methods
209
+
210
+ Please note the following methods are deprecated:
211
+
212
+ * `new_grayscale_color`
202
213
  * `new_brightness_color`
203
214
  * `new_contrast_color`
204
215
  * `new_hue_rotate_color`
@@ -6,5 +6,5 @@ yellow = ColorContrastCalc.color_from('yellow')
6
6
  orange = ColorContrastCalc.color_from('orange')
7
7
 
8
8
  report = 'The grayscale of %s is %s.'
9
- puts(format(report, yellow.hex, yellow.new_grayscale_color))
10
- puts(format(report, orange.hex, orange.new_grayscale_color))
9
+ puts(format(report, yellow.hex, yellow.with_grayscale))
10
+ puts(format(report, orange.hex, orange.with_grayscale))
@@ -3,6 +3,7 @@
3
3
  require 'color_contrast_calc/utils'
4
4
  require 'color_contrast_calc/checker'
5
5
  require 'color_contrast_calc/threshold_finder'
6
+ require 'color_contrast_calc/deprecated'
6
7
  require 'json'
7
8
 
8
9
  module ColorContrastCalc
@@ -13,6 +14,7 @@ module ColorContrastCalc
13
14
  # instances of Color class.
14
15
 
15
16
  class Color
17
+ include Deprecated::Color
16
18
  # @private
17
19
  RGB_LIMITS = [0, 255].freeze
18
20
 
@@ -102,7 +104,7 @@ module ColorContrastCalc
102
104
  # code is assigned instead.
103
105
  # @return [Color] New color with adjusted contrast
104
106
 
105
- def new_contrast_color(ratio, name = nil)
107
+ def with_contrast(ratio, name = nil)
106
108
  generate_new_color(Converter::Contrast, ratio, name)
107
109
  end
108
110
 
@@ -115,7 +117,7 @@ module ColorContrastCalc
115
117
  # code is assigned instead.
116
118
  # @return [Color] New color with adjusted brightness
117
119
 
118
- def new_brightness_color(ratio, name = nil)
120
+ def with_brightness(ratio, name = nil)
119
121
  generate_new_color(Converter::Brightness, ratio, name)
120
122
  end
121
123
 
@@ -128,7 +130,7 @@ module ColorContrastCalc
128
130
  # code is assigned instead.
129
131
  # @return [Color] New inverted color
130
132
 
131
- def new_invert_color(ratio = 100, name = nil)
133
+ def with_invert(ratio = 100, name = nil)
132
134
  generate_new_color(Converter::Invert, ratio, name)
133
135
  end
134
136
 
@@ -141,7 +143,7 @@ module ColorContrastCalc
141
143
  # code is assigned instead.
142
144
  # @return [Color] New hue rotation applied color
143
145
 
144
- def new_hue_rotate_color(degree, name = nil)
146
+ def with_hue_rotate(degree, name = nil)
145
147
  generate_new_color(Converter::HueRotate, degree, name)
146
148
  end
147
149
 
@@ -154,7 +156,7 @@ module ColorContrastCalc
154
156
  # code is assigned instead.
155
157
  # @return [Color] New saturated color
156
158
 
157
- def new_saturate_color(ratio, name = nil)
159
+ def with_saturate(ratio, name = nil)
158
160
  generate_new_color(Converter::Saturate, ratio, name)
159
161
  end
160
162
 
@@ -167,7 +169,7 @@ module ColorContrastCalc
167
169
  # code is assigned instead.
168
170
  # @return [Color] New grayscale color
169
171
 
170
- def new_grayscale_color(ratio = 100, name = nil)
172
+ def with_grayscale(ratio = 100, name = nil)
171
173
  generate_new_color(Converter::Grayscale, ratio, name)
172
174
  end
173
175
 
@@ -290,7 +292,7 @@ module ColorContrastCalc
290
292
  # The max contrast in this context means that of colors modified
291
293
  # by the operation defined at
292
294
  # * {https://www.w3.org/TR/filter-effects/#funcdef-contrast}
293
- # @return [Boolean] true if self.new_contrast_color(r) where r is
295
+ # @return [Boolean] true if self.with_contrast(r) where r is
294
296
  # greater than 100 returns the same color as self.
295
297
 
296
298
  def max_contrast?
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ColorContrastCalc
4
+ ##
5
+ # Collection of deprecated methods.
6
+
7
+ module Deprecated
8
+ def self.warn(old_method, new_method)
9
+ STDERR.puts "##{old_method} is deprecated. Use ##{new_method} instead"
10
+ end
11
+
12
+ module Color
13
+ # @deprecated Use {#with_contrast} instead
14
+ def new_contrast_color(ratio, name = nil)
15
+ Deprecated.warn(__method__, :with_contrast)
16
+ with_contrast(ratio, name)
17
+ end
18
+
19
+ # @deprecated Use {#with_brightness} instead
20
+ def new_brightness_color(ratio, name = nil)
21
+ Deprecated.warn(__method__, :with_brightness)
22
+ with_brightness(ratio, name)
23
+ end
24
+
25
+ # @deprecated Use {#with_invert} instead
26
+ def new_invert_color(ratio = 100, name = nil)
27
+ Deprecated.warn(__method__, :with_invert)
28
+ with_invert(ratio, name)
29
+ end
30
+
31
+ # @deprecated Use {#with_hue_rotate} instead
32
+ def new_hue_rotate_color(degree, name = nil)
33
+ Deprecated.warn(__method__, :with_hue_rotate)
34
+ with_hue_rotate(degree, name)
35
+ end
36
+
37
+ # @deprecated Use {#with_saturate} instead
38
+ def new_saturate_color(ratio, name = nil)
39
+ Deprecated.warn(__method__, :with_saturate)
40
+ with_saturate(ratio, name)
41
+ end
42
+
43
+ # @deprecated Use {#with_grayscale} instead
44
+ def new_grayscale_color(ratio = 100, name = nil)
45
+ Deprecated.warn(__method__, :with_grayscale)
46
+ with_grayscale(ratio, name)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -14,7 +14,7 @@ module ColorContrastCalc
14
14
  module Criteria
15
15
  # @private
16
16
 
17
- def self.threshold_criteria(level, fixed_rgb, other_rgb)
17
+ def self.define(level, fixed_rgb, other_rgb)
18
18
  if should_scan_darker_side?(fixed_rgb, other_rgb)
19
19
  return ToDarkerSide.new(level, fixed_rgb)
20
20
  end
@@ -32,16 +32,15 @@ module ColorContrastCalc
32
32
  end
33
33
 
34
34
  class SearchDirection
35
- attr_reader :level, :target_ratio, :fixed_luminance
35
+ attr_reader :target_contrast, :fixed_luminance
36
36
 
37
37
  def initialize(level, fixed_rgb)
38
- @level = level
39
- @target_ratio = Checker.level_to_ratio(level)
38
+ @target_contrast = Checker.level_to_ratio(level)
40
39
  @fixed_luminance = Checker.relative_luminance(fixed_rgb)
41
40
  end
42
41
 
43
42
  def sufficient_contrast?(rgb)
44
- contrast_ratio(rgb) >= @target_ratio
43
+ contrast_ratio(rgb) >= @target_contrast
45
44
  end
46
45
 
47
46
  def contrast_ratio(rgb)
@@ -53,28 +52,28 @@ module ColorContrastCalc
53
52
  class ToDarkerSide < SearchDirection
54
53
  # @private
55
54
 
56
- def round(r)
57
- (r * 10).floor / 10.0
55
+ def round(ratio)
56
+ (ratio * 10).floor / 10.0
58
57
  end
59
58
 
60
59
  # @private
61
60
 
62
61
  def increment_condition(contrast_ratio)
63
- contrast_ratio > @target_ratio
62
+ contrast_ratio > @target_contrast
64
63
  end
65
64
  end
66
65
 
67
66
  class ToBrighterSide < SearchDirection
68
67
  # @private
69
68
 
70
- def round(r)
71
- (r * 10).ceil / 10.0
69
+ def round(ratio)
70
+ (ratio * 10).ceil / 10.0
72
71
  end
73
72
 
74
73
  # @private
75
74
 
76
75
  def increment_condition(contrast_ratio)
77
- @target_ratio > contrast_ratio
76
+ @target_contrast > contrast_ratio
78
77
  end
79
78
  end
80
79
  end
@@ -96,13 +95,55 @@ module ColorContrastCalc
96
95
 
97
96
  # @private
98
97
 
99
- def sufficient_contrast?(fixed_rgb, other_rgb, level)
100
- target_ratio = Checker.level_to_ratio(level)
101
- ratio = Checker.contrast_ratio(fixed_rgb, other_rgb)
102
- ratio >= target_ratio
98
+ def sufficient_contrast?(ref_luminance, rgb, criteria)
99
+ luminance = Checker.relative_luminance(rgb)
100
+ ratio = Checker.luminance_to_contrast_ratio(ref_luminance, luminance)
101
+ ratio >= criteria.target_contrast
103
102
  end
104
103
 
105
104
  private :sufficient_contrast?
105
+
106
+ def rgb_with_better_ratio(color, criteria, last_r, passing_r)
107
+ closest = rgb_with_ratio(color, last_r)
108
+
109
+ if passing_r && !criteria.sufficient_contrast?(closest)
110
+ return rgb_with_ratio(color, passing_r)
111
+ end
112
+
113
+ closest
114
+ end
115
+
116
+ private :rgb_with_better_ratio
117
+
118
+ # @private
119
+
120
+ def find_ratio(other_color, criteria, init_ratio, init_width)
121
+ target_contrast = criteria.target_contrast
122
+ r = init_ratio
123
+ passing_r = nil
124
+
125
+ FinderUtils.binary_search_width(init_width, 0.01) do |d|
126
+ contrast = criteria.contrast_ratio(rgb_with_ratio(other_color, r))
127
+
128
+ passing_r = r if contrast >= target_contrast
129
+ break if contrast == target_contrast
130
+
131
+ r += criteria.increment_condition(contrast) ? d : -d
132
+ end
133
+
134
+ [r, passing_r]
135
+ end
136
+
137
+ private :find_ratio
138
+
139
+ # @private
140
+
141
+ def rgb_with_ratio(rgb, ratio)
142
+ raise(NotImplementedError,
143
+ "Implement ##{__method__} with arguments #{rgb} and #{ratio}")
144
+ end
145
+
146
+ private :rgb_with_ratio
106
147
  end
107
148
 
108
149
  ##
@@ -126,19 +167,27 @@ module ColorContrastCalc
126
167
  # adjusted from that of +other_rgb+
127
168
 
128
169
  def self.find(fixed_rgb, other_rgb, level = Checker::Level::AA)
129
- criteria = Criteria.threshold_criteria(level, fixed_rgb, other_rgb)
170
+ criteria = Criteria.define(level, fixed_rgb, other_rgb)
130
171
  w = calc_upper_ratio_limit(other_rgb) / 2.0
131
172
 
132
173
  upper_rgb = upper_limit_rgb(criteria, other_rgb, w * 2)
133
174
  return upper_rgb if upper_rgb
134
175
 
135
- r, sufficient_r = calc_brightness_ratio(other_rgb, criteria, w)
176
+ last_r, passing_r = find_ratio(other_rgb, criteria, w, w).map do |ratio|
177
+ criteria.round(ratio) if ratio
178
+ end
179
+
180
+ rgb_with_better_ratio(other_rgb, criteria, last_r, passing_r)
181
+ end
136
182
 
137
- generate_satisfying_color(other_rgb, criteria, r, sufficient_r)
183
+ def self.rgb_with_ratio(rgb, ratio)
184
+ Converter::Brightness.calc_rgb(rgb, ratio)
138
185
  end
139
186
 
187
+ private_class_method :rgb_with_ratio
188
+
140
189
  def self.upper_limit_rgb(criteria, other_rgb, max_ratio)
141
- limit_rgb = Converter::Brightness.calc_rgb(other_rgb, max_ratio)
190
+ limit_rgb = rgb_with_ratio(other_rgb, max_ratio)
142
191
  limit_rgb if exceed_upper_limit?(criteria, other_rgb, limit_rgb)
143
192
  end
144
193
 
@@ -152,44 +201,6 @@ module ColorContrastCalc
152
201
 
153
202
  private_class_method :exceed_upper_limit?
154
203
 
155
- def self.calc_brightness_ratio(other_rgb, criteria, w)
156
- target_ratio = criteria.target_ratio
157
- r = w
158
- sufficient_r = nil
159
-
160
- FinderUtils.binary_search_width(w, 0.01) do |d|
161
- contrast_ratio = calc_contrast_ratio(criteria, other_rgb, r)
162
-
163
- sufficient_r = r if contrast_ratio >= target_ratio
164
- break if contrast_ratio == target_ratio
165
-
166
- r += criteria.increment_condition(contrast_ratio) ? d : -d
167
- end
168
-
169
- [r, sufficient_r]
170
- end
171
-
172
- private_class_method :calc_brightness_ratio
173
-
174
- def self.generate_satisfying_color(other_rgb, criteria, r, sufficient_r)
175
- nearest = Converter::Brightness.calc_rgb(other_rgb, criteria.round(r))
176
-
177
- if sufficient_r && !criteria.sufficient_contrast?(nearest)
178
- return Converter::Brightness.calc_rgb(other_rgb,
179
- criteria.round(sufficient_r))
180
- end
181
-
182
- nearest
183
- end
184
-
185
- private_class_method :generate_satisfying_color
186
-
187
- def self.calc_contrast_ratio(criteria, other_rgb, r)
188
- criteria.contrast_ratio(Converter::Brightness.calc_rgb(other_rgb, r))
189
- end
190
-
191
- private_class_method :calc_contrast_ratio
192
-
193
204
  # @private
194
205
 
195
206
  def self.calc_upper_ratio_limit(rgb)
@@ -221,68 +232,49 @@ module ColorContrastCalc
221
232
 
222
233
  def self.find(fixed_rgb, other_rgb, level = Checker::Level::AA)
223
234
  other_hsl = Utils.rgb_to_hsl(other_rgb)
224
- criteria = Criteria.threshold_criteria(level, fixed_rgb, other_rgb)
235
+ criteria = Criteria.define(level, fixed_rgb, other_rgb)
225
236
  max, min = determine_minmax(fixed_rgb, other_rgb, other_hsl[2])
226
237
 
227
- boundary_color = lightness_boundary_color(fixed_rgb, max, min, level)
228
- return boundary_color if boundary_color
238
+ boundary_rgb = lightness_boundary_rgb(fixed_rgb, max, min, criteria)
239
+ return boundary_rgb if boundary_rgb
229
240
 
230
- l, sufficient_l = calc_lightness_ratio(other_hsl, criteria, max, min)
241
+ last_l, passing_l = find_ratio(other_hsl, criteria,
242
+ (max + min) / 2.0, max - min)
231
243
 
232
- generate_satisfying_color(other_hsl, criteria, l, sufficient_l)
244
+ rgb_with_better_ratio(other_hsl, criteria, last_l, passing_l)
233
245
  end
234
246
 
235
- def self.determine_minmax(fixed_rgb, other_rgb, init_l)
236
- scan_darker_side = Criteria.should_scan_darker_side?(fixed_rgb,
237
- other_rgb)
238
- scan_darker_side ? [init_l, 0] : [100, init_l] # [max, min]
239
- end
240
-
241
- private_class_method :determine_minmax
242
-
243
- def self.lightness_boundary_color(rgb, max, min, level)
244
- if min.zero? && !sufficient_contrast?(Rgb::BLACK, rgb, level)
245
- return Rgb::BLACK
247
+ def self.rgb_with_ratio(hsl, ratio)
248
+ if hsl[2] != ratio
249
+ hsl = hsl.dup
250
+ hsl[2] = ratio
246
251
  end
247
252
 
248
- if max == 100 && !sufficient_contrast?(Rgb::WHITE, rgb, level)
249
- return Rgb::WHITE
250
- end
253
+ Utils.hsl_to_rgb(hsl)
251
254
  end
252
255
 
253
- private_class_method :lightness_boundary_color
256
+ private_class_method :rgb_with_ratio
254
257
 
255
- def self.calc_lightness_ratio(other_hsl, criteria, max, min)
256
- h, s, = other_hsl
257
- l = (max + min) / 2.0
258
- sufficient_l = nil
259
-
260
- FinderUtils.binary_search_width(max - min, 0.01) do |d|
261
- contrast_ratio = criteria.contrast_ratio(Utils.hsl_to_rgb([h, s, l]))
262
-
263
- sufficient_l = l if contrast_ratio >= criteria.target_ratio
264
- break if contrast_ratio == criteria.target_ratio
265
-
266
- l += criteria.increment_condition(contrast_ratio) ? d : -d
267
- end
268
-
269
- [l, sufficient_l]
258
+ def self.determine_minmax(fixed_rgb, other_rgb, init_l)
259
+ on_darker_side = Criteria.should_scan_darker_side?(fixed_rgb, other_rgb)
260
+ on_darker_side ? [init_l, 0] : [100, init_l] # [max, min]
270
261
  end
271
262
 
272
- private_class_method :calc_lightness_ratio
273
-
274
- def self.generate_satisfying_color(other_hsl, criteria, l, sufficient_l)
275
- h, s, = other_hsl
276
- nearest = Utils.hsl_to_rgb([h, s, l])
263
+ private_class_method :determine_minmax
277
264
 
278
- if sufficient_l && !criteria.sufficient_contrast?(nearest)
279
- return Utils.hsl_to_rgb([h, s, sufficient_l])
265
+ def self.lightness_boundary_rgb(rgb, max, min, criteria)
266
+ if min.zero? && !sufficient_contrast?(Checker::Luminance::BLACK,
267
+ rgb, criteria)
268
+ return Rgb::BLACK
280
269
  end
281
270
 
282
- nearest
271
+ if max == 100 && !sufficient_contrast?(Checker::Luminance::WHITE,
272
+ rgb, criteria)
273
+ return Rgb::WHITE
274
+ end
283
275
  end
284
276
 
285
- private_class_method :generate_satisfying_color
277
+ private_class_method :lightness_boundary_rgb
286
278
  end
287
279
  end
288
280
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ColorContrastCalc
4
- VERSION = '0.3.0'
4
+ VERSION = '0.4.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: color_contrast_calc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - HASHIMOTO, Naoki
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-03-20 00:00:00.000000000 Z
11
+ date: 2018-04-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -114,6 +114,7 @@ files:
114
114
  - lib/color_contrast_calc/color.rb
115
115
  - lib/color_contrast_calc/converter.rb
116
116
  - lib/color_contrast_calc/data/color_keywords.json
117
+ - lib/color_contrast_calc/deprecated.rb
117
118
  - lib/color_contrast_calc/shim.rb
118
119
  - lib/color_contrast_calc/sorter.rb
119
120
  - lib/color_contrast_calc/threshold_finder.rb