tincture-apca 1.0.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 +7 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE.md +12 -0
- data/README.md +53 -0
- data/lib/tincture/apca/version.rb +7 -0
- data/lib/tincture/apca.rb +118 -0
- metadata +63 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: '03519433f7f021e7c641da9814503f7175233ebab635f70599c419616ac18d15'
|
|
4
|
+
data.tar.gz: 58cb22824f9af6a9d99970e0213b8a761b8597fbcf65aa16b60d51a40ce61ca1
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 3014dc7a59b1deb07bc0686482cb4f2a077df8a73f9db6888f7e5abb140e0c9d391b35459e429ed70d232e91dd6445d9f38582a470f66450e221effb10e78c4e
|
|
7
|
+
data.tar.gz: 05b97f7f2f23d18296b530945be9fb9c5cfea664b5e3fc36dfc3340c96761572cc64a84bc116a8cd31546d6444180909f0b94db7b536a883d1bcb3a28c703d41
|
data/CHANGELOG.md
ADDED
data/LICENSE.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Licence
|
|
2
|
+
|
|
3
|
+
This gem is a port of [apca-w3](https://github.com/Myndex/apca-w3) 0.1.9 (base algorithm 0.0.98G-4g) and is distributed under the apca-w3 licence, not MIT: https://github.com/Myndex/apca-w3/blob/master/LICENSE.md
|
|
4
|
+
|
|
5
|
+
APCA is copyright © 2019-2023 Andrew Somers and Myndex Research, patent pending.
|
|
6
|
+
|
|
7
|
+
In short, and the licence itself governs:
|
|
8
|
+
|
|
9
|
+
- Use is allowed only for web content, in support of the WCAG accessibility guidelines. Other uses, such as print or PDF, fall under AGPL v3.
|
|
10
|
+
- A commercial product that uses it must give Myndex free access to audit the code on request.
|
|
11
|
+
- The algorithm and constants must not change, except to port them, and must be kept current.
|
|
12
|
+
- The name "APCA" may describe only a correct, current implementation.
|
data/README.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Tincture APCA
|
|
2
|
+
|
|
3
|
+
[](https://github.com/andycroll/tincture-apca/actions/workflows/ci.yml)
|
|
4
|
+
|
|
5
|
+
APCA contrast for Tincture colours
|
|
6
|
+
|
|
7
|
+
> [!WARNING]
|
|
8
|
+
> APCA is © Andrew Somers and Myndex Research, patent pending. Its [licence](LICENSE.md) allows use only for web content, in support of the WCAG accessibility guidelines. Other uses, such as print or PDF, fall under AGPL v3. A commercial product that uses it must give Myndex free access to audit the code on request.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
Add these lines to your Gemfile:
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
gem "tincture"
|
|
16
|
+
gem "tincture-apca", require: false
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Then require it where web content is built, not globally:
|
|
20
|
+
|
|
21
|
+
```ruby
|
|
22
|
+
require "tincture/apca"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
27
|
+
Measure APCA lightness contrast (Lc) for text on a background
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
Tincture::Color.parse("#888").apca_contrast("#fff") # 63.06
|
|
31
|
+
Tincture::Color.parse("#fff").apca_contrast("#888") # -68.54
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Positive is dark text on light, negative is light on dark. For body text, Lc 75 is the minimum and Lc 90 preferred.
|
|
35
|
+
|
|
36
|
+
Pick black or white text by APCA
|
|
37
|
+
|
|
38
|
+
```ruby
|
|
39
|
+
background.contrast_color(method: :apca)
|
|
40
|
+
background.contrast_color(among: ["#1f2937", "white"], method: :apca)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
This is a port of [apca-w3](https://github.com/Myndex/apca-w3) 0.1.9 (algorithm 0.0.98G-4g), checked against its test values.
|
|
44
|
+
|
|
45
|
+
## Development
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
bundle install
|
|
49
|
+
bundle exec rake # tests and RuboCop
|
|
50
|
+
bundle exec rake rdoc # API docs in doc/
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
To release, set the version in `lib/tincture/apca/version.rb`, date the changelog entry, commit, and push a `vX.Y.Z` tag. GitHub Actions runs the checks and publishes the gem to rubygems.org through trusted publishing.
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'tincture'
|
|
4
|
+
require_relative 'apca/version'
|
|
5
|
+
|
|
6
|
+
module Tincture # :nodoc:
|
|
7
|
+
# [APCA](https://git.apcacontrast.com/) lightness contrast (Lc), the
|
|
8
|
+
# perceptual contrast method drafted for WCAG 3. Requiring
|
|
9
|
+
# `tincture/apca` adds ColorMethods#apca_contrast to Tincture::Color and
|
|
10
|
+
# `method: :apca` to Tincture::Color#contrast_color.
|
|
11
|
+
#
|
|
12
|
+
# A port of [apca-w3](https://github.com/Myndex/apca-w3) 0.1.9: base
|
|
13
|
+
# algorithm 0.0.98G-4g with its approved constants.
|
|
14
|
+
#
|
|
15
|
+
# **Licence restriction.** APCA is copyright © 2019–2023 Andrew Somers and
|
|
16
|
+
# Myndex Research, patent pending. Its licence allows use only for web
|
|
17
|
+
# content, in support of the WCAG accessibility guidelines. Other uses,
|
|
18
|
+
# such as print or PDF, fall under AGPL v3. A commercial product that uses
|
|
19
|
+
# it must give Myndex free access to audit the code on request. The
|
|
20
|
+
# algorithm and constants must not change, except to port them, and must
|
|
21
|
+
# be kept current. See the
|
|
22
|
+
# [licence](https://github.com/Myndex/apca-w3/blob/master/LICENSE.md).
|
|
23
|
+
module Apca
|
|
24
|
+
# Names match apca-w3's SA98G, so each value can be checked against it.
|
|
25
|
+
SA98G = {
|
|
26
|
+
mainTRC: 2.4,
|
|
27
|
+
sRco: 0.2126729,
|
|
28
|
+
sGco: 0.7151522,
|
|
29
|
+
sBco: 0.0721750,
|
|
30
|
+
normBG: 0.56,
|
|
31
|
+
normTXT: 0.57,
|
|
32
|
+
revTXT: 0.62,
|
|
33
|
+
revBG: 0.65,
|
|
34
|
+
blkThrs: 0.022,
|
|
35
|
+
blkClmp: 1.414,
|
|
36
|
+
scaleBoW: 1.14,
|
|
37
|
+
scaleWoB: 1.14,
|
|
38
|
+
loBoWoffset: 0.027,
|
|
39
|
+
loWoBoffset: 0.027,
|
|
40
|
+
deltaYmin: 0.0005,
|
|
41
|
+
loClip: 0.1
|
|
42
|
+
}.freeze
|
|
43
|
+
|
|
44
|
+
module_function
|
|
45
|
+
|
|
46
|
+
# Lc for text on a background, from their #luminance values. Positive for
|
|
47
|
+
# dark text on light, negative for light text on dark, up to about ±108.
|
|
48
|
+
# For body text, Lc 75 is the minimum and Lc 90 preferred.
|
|
49
|
+
#
|
|
50
|
+
#: (Float text_y, Float background_y) -> Float
|
|
51
|
+
def contrast(text_y, background_y)
|
|
52
|
+
text_y, background_y = [text_y, background_y].map { soft_clamped(it) }
|
|
53
|
+
|
|
54
|
+
lc =
|
|
55
|
+
if (background_y - text_y).abs < SA98G[:deltaYmin] then 0.0
|
|
56
|
+
elsif background_y > text_y then dark_on_light(text_y, background_y)
|
|
57
|
+
else light_on_dark(text_y, background_y)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
lc * 100
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# APCA's screen luminance (Y) for 0–255 sRGB channels. Not the same as
|
|
64
|
+
# WCAG 2 relative luminance.
|
|
65
|
+
#
|
|
66
|
+
#: ([Integer, Integer, Integer] rgb) -> Float
|
|
67
|
+
def luminance((red, green, blue))
|
|
68
|
+
(SA98G[:sRco] * linear(red)) + (SA98G[:sGco] * linear(green)) + (SA98G[:sBco] * linear(blue))
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def linear(channel) = (channel / 255.0)**SA98G[:mainTRC] # :nodoc:
|
|
72
|
+
|
|
73
|
+
def soft_clamped(luminance) # :nodoc:
|
|
74
|
+
luminance > SA98G[:blkThrs] ? luminance : luminance + ((SA98G[:blkThrs] - luminance)**SA98G[:blkClmp])
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def dark_on_light(text_y, background_y) # :nodoc:
|
|
78
|
+
sapc = ((background_y**SA98G[:normBG]) - (text_y**SA98G[:normTXT])) * SA98G[:scaleBoW]
|
|
79
|
+
sapc < SA98G[:loClip] ? 0.0 : sapc - SA98G[:loBoWoffset]
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def light_on_dark(text_y, background_y) # :nodoc:
|
|
83
|
+
sapc = ((background_y**SA98G[:revBG]) - (text_y**SA98G[:revTXT])) * SA98G[:scaleWoB]
|
|
84
|
+
sapc > -SA98G[:loClip] ? 0.0 : sapc + SA98G[:loWoBoffset]
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
private_class_method :linear, :soft_clamped, :dark_on_light, :light_on_dark
|
|
88
|
+
|
|
89
|
+
# Added to Tincture::Color.
|
|
90
|
+
module ColorMethods
|
|
91
|
+
# APCA lightness contrast (Lc) of this colour as text on `background`.
|
|
92
|
+
# Positive for dark text on light, negative for light on dark.
|
|
93
|
+
# Translucent text is blended onto the background first.
|
|
94
|
+
#
|
|
95
|
+
# **Licence restriction:** web content only, in support of WCAG. See
|
|
96
|
+
# Apca.
|
|
97
|
+
#
|
|
98
|
+
# Tincture::Color.parse("#888").apca_contrast("#fff") # => 63.06…
|
|
99
|
+
#
|
|
100
|
+
#: (String | Color background) -> Float
|
|
101
|
+
def apca_contrast(background)
|
|
102
|
+
background = Color.parse(background)
|
|
103
|
+
text = opaque? ? self : blended_over(background)
|
|
104
|
+
|
|
105
|
+
Apca.contrast(Apca.luminance(text.rgb), Apca.luminance(background.rgb))
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
private
|
|
109
|
+
|
|
110
|
+
def blended_over(background)
|
|
111
|
+
Color.rgb(*rgb.zip(background.rgb).map { |mine, theirs| (theirs * (1 - alpha)) + (mine * alpha) })
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
Color.include(Apca::ColorMethods)
|
|
117
|
+
Color.contrast_scorers[:apca] = ->(text, background) { text.apca_contrast(background).abs }
|
|
118
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: tincture-apca
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Andy Croll
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: tincture
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '1.0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '1.0'
|
|
26
|
+
description: Adds APCA lightness contrast (Lc) to Tincture::Color, ported from apca-w3.
|
|
27
|
+
Its licence restricts use to web content in support of WCAG.
|
|
28
|
+
email:
|
|
29
|
+
- andy@goodscary.com
|
|
30
|
+
executables: []
|
|
31
|
+
extensions: []
|
|
32
|
+
extra_rdoc_files: []
|
|
33
|
+
files:
|
|
34
|
+
- CHANGELOG.md
|
|
35
|
+
- LICENSE.md
|
|
36
|
+
- README.md
|
|
37
|
+
- lib/tincture/apca.rb
|
|
38
|
+
- lib/tincture/apca/version.rb
|
|
39
|
+
homepage: https://github.com/andycroll/tincture-apca
|
|
40
|
+
licenses:
|
|
41
|
+
- LicenseRef-apca-w3
|
|
42
|
+
metadata:
|
|
43
|
+
source_code_uri: https://github.com/andycroll/tincture-apca
|
|
44
|
+
changelog_uri: https://github.com/andycroll/tincture-apca/blob/main/CHANGELOG.md
|
|
45
|
+
rubygems_mfa_required: 'true'
|
|
46
|
+
rdoc_options: []
|
|
47
|
+
require_paths:
|
|
48
|
+
- lib
|
|
49
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '3.4'
|
|
54
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
55
|
+
requirements:
|
|
56
|
+
- - ">="
|
|
57
|
+
- !ruby/object:Gem::Version
|
|
58
|
+
version: '0'
|
|
59
|
+
requirements: []
|
|
60
|
+
rubygems_version: 4.0.20
|
|
61
|
+
specification_version: 4
|
|
62
|
+
summary: APCA contrast for Tincture colours, for WCAG web content only
|
|
63
|
+
test_files: []
|